ts 공부를 시작한지 얼마 안 되어서, js파일을 ts로 점차 수정하는데 소스에 any가 남발하고 있는 중이다.
이런 코드라면 ts를 쓰는 이유가 없는 것 같다 생각했다.
더욱 ts 답게 고칠 수 있는 방법을 찾던 중 unknow 타입에 대해 접하게 되었다.
// Anything is assignable to unknown
function f21<T>(pAny: any, pNever: never, pT: T) {
let x: unknown;
x = 123;
x = "hello";
x = [1, 2, 3];
x = new Error();
x = x;
x = pAny;
x = pNever;
x = pT;
}
// unknown assignable only to itself and any
function f22(x: unknown) {
let v1: any = x;
let v2: unknown = x;
let v3: object = x; // Error
let v4: string = x; // Error
let v5: string[] = x; // Error
let v6: {} = x; // Error
let v7: {} | null | undefined = x; // Error
}
intersection (&)
하면 대상 타입을 반환union (|)
하면 unknown 타입을 반환// 1. intersection
type T00 = unknown & null; // null
type T01 = unknown & undefined; // undefined
type T02 = unknown & null & undefined; // null & undefined (which becomes never)
type T03 = unknown & string; // string
type T04 = unknown & string[]; // string[]
type T05 = unknown & unknown; // unknown
type T06 = unknown & any; // any
// 2. union
type T10 = unknown | null; // unknown
type T11 = unknown | undefined; // unknown
type T12 = unknown | null | undefined; // unknown
type T13 = unknown | string; // unknown
type T14 = unknown | string[]; // unknown
type T15 = unknown | unknown; // unknown
type T16 = unknown | any; // any
type T30<T> = unknown extends T ? true : false; // Deferred
type T31<T> = T extends unknown ? true : false; // Deferred (so it distributes)
type T32<T> = never extends T ? true : false; // true
type T33<T> = T extends never ? true : false; // Deferred
type T40 = keyof any; // string | number | symbol
type T41 = keyof unknown; // never
//
function f10(x: unknown) {
x == 5;
x !== 10;
x >= 0; // Error
x + 1; // Error
x * 2; // Error
-x; // Error
+x; // Error
}
function f11(x: unknown) {
x.foo; // Error
x[5]; // Error
x(); // Error
new x(); // Error
}
// typeof, instanceof, and user defined type predicates
declare function isFunction(x: unknown): x is Function;
function f20(x: unknown) {
if (typeof x === "string" || typeof x === "number") {
x; // string | number
}
if (x instanceof Error) {
x; // Error
}
if (isFunction(x)) {
x; // Function
}
}
type T50<T> = { [P in keyof T]: number };
type T51 = T50<any>; // { [x: string]: number }
type T52 = T50<unknown>; // {}
function f26(x: {}, y: unknown, z: any) {
let o1 = { a: 42, ...x }; // { a: number }
let o2 = { a: 42, ...x, ...y, ...z }; // Error at '...y'
}
function f27(): unknown {} // Error. 반환값 필요
const x: any = {
a: "a-value",
b: "b-value"
};
x.a; // OK
x.c = "c-value"; // OK
const y: unknown = {
a: "a-value",
b: "b-value"
};
y.a; // ERROR
(y as {a: string; b: string; }).a; // OK
y.c = "c-value"; // ERROR
어떤 타입이 올지 모르는 상황에서 더욱 type-safe 하도록 작성하려는 경우에 unknown 타입을 활용하기
참고
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type
https://mainawycliffe.dev/blog/typescript-use-unknown-instead-of-any/