type TState = {
name: string;
capital: string;
}
interface IState {
name: string;
capital: string;
}
type TDict = { [key: string]: string };
interface IDict {
[key: string]: string;
}
type TFn = (x:number) => string;
interface IFn {
(x: number): string;
}
type TPair<T> = {
first: T;
second: T;
}
interface IPair<T> {
first: T;
second: T;
}
interface IStateWithPop extends TState {
population: number;
}
type TStateWithPop = IState & { population: number; }
IStateWithPop과 TStateWithPop은 동일하다. 타입과 &를 사용해야 한다.class StateT implements TState {
name: string = '';
capital: string = '';
}
class StateI implements IState {
name: string = '';
capital: string = '';
}
type Input = { /* ... */ };
type Output = { /* ... */ };
interface VariableMap {
[name: string]: Input | Output;
}
type NamedVariable = (Input | Output) & { name: string };
type Pair = [number, number];
type StringList = string[];
type NamedNums = [string, ...number[]];
interface IState {
name: string;
capital: stirng;
}
interface IState {
population: number;
}
const wyoming: IState = {
name: 'Wyoming',
capital: 'Cheyenne',
population: 500_000,
}; // 정상
선언 병합이라고 한다.복잡한 타입이라면 타입 별칭을 사용하는게 좋다.일관성과 보강의 관점에서 고려API에 대한 타입 선언을 작성해야 한다면 인터페이스를 사용하는게 좋다. 프로젝트 내부적으로 사용되는 타입은 바뀌어서는 안된다. 타입을 사용해야 한다.interface State {
userId: string;
pageTitle: string;
recentFiles: string[];
pageContents: string;
}
interface TopNavState {
userId: stirng;
pageTitle: string;
recentFiles: string[];
}
전체 애플리케이션의 상태를 표현하는 State 타입과 단지 부분만 표현하는 TopNavState가 있는 경우이다.
TopNavState를 확장하여 State를 구성하기보다, State의 부분 집합으로 TopNavState를 정의하는 것이 바람직하다. 이 방법이 전체 앱의 상태를 하나의 인터페이스로 유지할 수 있게 해준다.
type TopNavState = {
[k in 'userId' | 'pageTitle' | 'recentFiles']: State[k]
};
맵핑된 타입을 사용해서 반복을 최소화 할 수 있다.type Rocket - {[property: string]: string};
const rocket: Rocket = {
name: 'Falcon 9',
variant: 'v1.0',
thrust: '4,940 kN',
};
인덱스 시그니처를 명시하면 유연하게 매핑을 표현할 수 있다.type Vec3D = Record<'x', 'y', 'z', number>;
// Type Vec3D = {
// x: number;
// y: number;
// z: number;
// }
type ABC = { [k in 'a' | 'b' | 'c']: k extends 'b' ? string : number};
// Type Vec3D = {
// x: number;
// y: string;
// z: number;
// }
for-in 루프는 for-of 또는 C 스타일 for 루프에 비해 몇 배나 느리다.function arraySum(arr: readonly number[]){
let sum = 0, num;
while((num = arr.pop()) !== undefined){
// ~~~ 'readonly number[]' 형식에 'pop' 속성이 없습니다.
sum += num;
}
return sum;
}
함수가 매개변수를 변경하지 않는다고 가정한다. 그러나 명시적으로 readonly 접근 제어자를 사용하는것이 컴파일러와 사람 모두에게 좋다. 그 함수를 호출하는 다른 함수도 모두 readonly로 만들어야 한다.다른 라이브러리에 있는 함수를 호출하는 경우, 타입 선언을 바꿀 수 없으므로 타입 단언문을 사용해야 한다.function parseTaggedText(lines: string[]): string[][] {
const currPara: readonly string[] = [];
const paragraphs: string[][] = [];
const addParagraph = () => {
if (currPara.length) {
paragraphs.push(
currPara
// ~~~~~~~~ Type 'readonly string[]' is 'readonly' and
// cannot be assigned to the mutable type 'string[]'
);
currPara.length = 0; // Clear lines
// ~~~~~~ Cannot assign to 'length' because it is a read-only
// property
}
};
for (const line of lines) {
if (!line) {
addParagraph();
} else {
currPara.push(line);
// ~~~~ Property 'push' does not exist on type 'readonly string[]'
}
}
addParagraph();
return paragraphs;
}
let으로 선언하고 변환이 없는 메서드를 사용함으로써 두 개의 오류를 고칠 수 있다. let currPara: readonly string[] = [];
// ...
currPara = []; // 배열을 비움
// ...
currPara = currPara.concat([line]);
원본을 수정하지 않고 새 배열을 반환한다.let, readonly로 수정함으로써 currPara 변수는 가리키는 배열을 자유롭게 변경할 수 있지만, 그 배열 자체는 변경하지 못한다.currPara의 복사본을 만드는 방법paragraphs.push([...currPara]);
paragraphs(그리고 함수의 반환 타입)를 readonly string[]의 배열로 변경하는 방법const paragraphs: (readonly string[])[] = [];
이미 함수가 반환한 값에 대해 영향을 끼치는 것이 맞는 방법인지 고민해야 한다.단언문을 쓰는 방법paragraphs.push(currPara as string[]);
readonly는 얕게 동작한다. 객체의 readonly 배열이 있다면, 그 객체 자체는 readonly가 아니다.깊은 readonly 타입을 사용할 수 있지만 만들기 까다롭기 때문에 라이브러리를 사용하는게 낫다.ts-essentials에 있는 DeepReadonly 제너릭을 사용하면 된다.interface ViewProps {
// data
xs: number[];
ys: number[];
// display
xRange: [number,number];
yRange: [number, number];
color: string;
// event
onClick: (x:number, y: number, index: number) => void;
}
const REQUIRES_UPDATE: {[k in keyof ViewProps]: boolean} = {
xs: true,
ys: true,
xRange: true,
yRange: true,
color: true,
onClick: false
}
function shouldUpdate(
oldProps: ViewProps,
newProps: ViewProps,
) {
let k: keyof ViewProps;
for (k in oldProps){
if(oldProps[k] !== newProps[k] && REQUIRES_UPDATE[k]){
return true;
}
}
}
[k in keyof ScatterProps]은 타입 체커에게 REQUIRES_UPDATE가 ScatterProps과 동일한 속성을 가져야 한다는 정보를 제공한다.