any
는 모든 타입이 올 수 있다. any
는 타입 검사를 수행하지 않도록 명시적으로 지시하기 때문에 안정성이 부족하다는 문제점이 있다. unknown
타입이 훨씬 안전하다. unknown
은 진정한 top 타입이다. any
와 유사하지만, 주요 차이점은 unknown
타입의 값을 훨씬 더 제한적으로 취급한다. unknown
타입 값의 속성에 직접 접근할 수 없다. unknown
타입은 top 타입이 아닌 타입에는 할당할 수 없다. unknown
타입에 접근 하려면 타입을 좁혀서 검사를 해야한다. 이때문에 unknown
이 any
보다 훨씬 안전하다. function hello(name: unknown) {
// typeof로 name의 타입을 검사한다.
if(typeof name === 'string') {
console.log(name.toUpperCase());
}
// 타입을 검사하지 않으면 에러가 발생한다.
console.log(name.toUpperCase()); // Error: 'name' is of type 'unknown'.
}
is
키워드, 특정 타입 function typePredicate(input: WideType): input is NarrowType;
keyof
연산자는 인터페이스의 모든 키를 유니언 타입으로 생성한다.
interface Student {
name: string;
age: number;
}
function students(student: Student, key: keyof Student) {
return student[key]; // OK
}
const student = {
name: "Smith",
age: 22
}
students(student, "name"); // OK
students(student, "age"); // OK
students(student, "address"); // Error: Argument of type '"address"' is not assignable to parameter of type 'keyof Person'.
typeof
는 제공되는 값의 타입을 반환한다. typeof
연산자와 다르다. 타입스크립트의 typeof
연산자는 타입스크립트에서만 사용되며 컴파일하면 사라진다. const original = {
medium: "movie",
title: "Mean Girls",
}
let adaptation: typeof original;
if(Math.random() > 0.5) {
adaptation = { ...original, medium: "play" }; // OK
} else {
adaptation = { ...original, medium: 2 };
// Error: Type 'number' is not assignable to type 'string'.
}
typeof
는 값의 타입을 검색하고, keyof
는 타입에 허용된 키를 검색한다. const ratings = {
imdb: 8.4,
metacritic: 82,
}
// 인터페이스 생성 대신, keyof typeof 키워드를 사용해
// 키가 ratings 값 타입의 키 중 하나여야 함을 나타낸다.
function logRating(key: keyof typeof ratings) {
console.log(ratings[key]);
}
logRating("imdb"); // OK
logRating("invalid"); // Error:
// Argument of type '"invalid"' is not assignable
// to parameter of type '"imdb" | "metacritic"'.
as
키워드를 작성한다. const rawData = '["grace", "frankie"]';
// 타입: any
JSON.parse(rawData);
// 타입: string[]
JSON.parse(rawData) as string[];
// 타입: [string, string]
JSON.parse(rawData) as [string, string];
// 타입: ["grace", "frankie"]
JSON.parse(rawData) as ["grace", "frankie"];
📌 이전에는
item as type
대신<type>item
같은 구문을 사용했는데, 이 구문은 JSX와 호환되지 않고 .tsx 파일에서도 작동하지 않기 때문에 권장하지 않는다.
타입 어서션을 가능한 사용하지 않는 것이 좋다. 그러나 타입 어서션이 유용하고 심지어 필요한 경우가 종종 있다.
try {
// 오류를 발생시키는 코드
} catch(error) {
// Error 객체라고 가정된 error의 message 속성에 접근한다.
console.warn("Oh no!", (error as Error).message);
}
try {
// 오류를 발생시키는 코드
} catch(error) {
// error가 Error 클래스의 인스턴스인지를 검사해
// 콘솔에 Error의 message를 출력할지 error 자체를 출력할지 여부를 확인함
console.warn("Oh no!", error instanceof Error ? error.message : error);
}
!
키워드를 사용하면 null과 undefined를 제외한 전체 타입을 작성하지 않아도 된다. // 타입 유추: Date | undefined
let maybeDate = Math.random() > 0.5
? undefined
: new Date();
// 타입이 Date라고 간주됨
maybeDate as Date;
// 타입이 Date라고 간주됨
maybeDate!;
// 원시 타입은 서로 관련이 없으므로 하나의 원시타입에서 다른 원시타입으로 전환하는 것은 허용되지 않는다.
let myValue = "string" as number;
// Error: Conversion of type 'string' to type 'number' may be a mistake
// because neither type sufficiently overlaps with the other.
// If this was intentional, convert the expression to 'unknown' first.
any
나 unknown
같은 top 타입으로 전환한 다음, 그 결과를 관련 없는 타입으로 전환한다. // 허용되지만 이렇게 사용하면 안됨
let myValue = "string" as unknown as number;
as const
는 다음 세 가지 규칙을 적용한다. // 배열은 가변 배열이 아닌 읽기 전용 튜플로 취급
// 타입: (number | string)[]
[0, ''];
// 타입: readonly [0, '']
[0, ''] as const;
as const
를 사용하면 원시 타입을 좀 더 구체적인 특정 리터럴로 만들 수 있다.
// 타입: () => string
const getName = () => "Maria Bamford";
// 타입: () => "Maria Bamford"
const getNameConst = () => "Maria Bamford" as const;
as const
를 사용하면 readonly
가 된다. const risa = {
name: "Risa", // name: string
age: 20, // age: number
arr: ["apple", "banana"] // arr: string[]
};
const risaConst = {
name: "Risa", // name: "Risa"
age: 20, // age: 20
arr: ["apple", "banana"] // arr: readonly ["apple", "banana"]
} as const;
risaConst.name; // OK
risaConst.age; // OK
risaConst.name = "Maya"; // Error: Cannot assign to 'name' because it is a read-only property.
risaConst.arr[0] = "orange"; // Error: Cannot assign to '0' because it is a read-only property.