Search

[Typescript] unknown vs any type

subtitle
unknown vs any type
Tags
typescript
Created
2021/04/27
2 more properties

Unknown Type

unknown VS any

unknown type은 typescript 3.0 버전에서 새로 소개된 타입이다. any 타입처럼 unknown 타입에는 어떤 타입의 값도 할당할 수 있다. 이는 둘의 공통점이다. 다른 점은, any 타입의 값은 어느 타입의 변수에도 할당될 수 있으나, unknown 타입의 값은 any와 unknown 타입을 제외한 타입의 변수에는 할당이 불가능하다.
조금 더 쉽게 코드로 예를 들어보자.
let notSure: unknown; notSure = 1; notSure = "maybe a string instead"; // any type에는 unknown 타입 할당 가능 let anyType: any; anyType = notSure; // any, unknown 이외의 type에는 unknown 타입 할당 불가능 let numberType: number; numberType = notSure; // compile error!
TypeScript
unknown 타입 변수에는 number, string 등 어떤 타입의 값도 할당될 수 있다. 그러나 number type의 변수 numberType 에 unknown 타입의 값을 할당하려고 하면 Type 'unknown' is not assignable to type 'number' 라는 컴파일 에러가 난다. 위에서 언급한 것처럼 unknown 타입의 값을 any, unknown 외의 타입의 변수에 할당하려고 하면 에러가 난다.

등장 배경

any 타입은 타입 체킹도 안하고 어떤 타입에도 할당될 수 있는 관대한 타입이다. any 타입은 프로그래밍을 할 때는 편하지만, 아래 코드처럼 버그를 야기할 수 있는 위험이 있기도 하다.
any 타입의 foo 변수에는 10이 할당되었다. 이후 객체도 아닌데 객체처럼 접근하거나 함수로 호출하는 등 다음의 코드는 온갖 에러를 발생시킬 것이다. 하지만 any 타입으로 지정했으니 typescript에서는 에러를 감지하지 못한다.
let foo: any = 10; // All of these will throw errors, but TypeScript // won't complain since `foo` has the type `any`. foo.x.prop; foo.y.prop; foo.z.prop; foo(); new foo(); upperCase(foo); foo `hello world!`; function upperCase(x: string) { return x.toUpperCase(); }
TypeScript
source of code: microsoft dev blogs, RC announcement
this can be any value, so you must perform some type of checking before you use it - in microsoft dev blog
RC 발표에 따르면, any처럼 어떤 타입의 value든 할당할 수 있으면서 실제로 사용할 때는 개발자로 하여금 타입을 체킹하도록 만들 수 있는 타입이 필요했다. 그래서 조금 덜 수용적인 unknown 타입을 만들게 된 것이다.
사용자로부터 입력을 받거나 잘 알려지지 않은 외부 API를 사용하는 등 실제로 어떤 값이 올 지 모를 때, 어떤 값이든 할당할 수 있지만 정작 이후에 그 값을 사용할 때는 타입 체킹을 해서 안전하게 사용하게 하기 위해 쓸 수 있다.
아까와 달리 위의 코드에서 any를 unknown 타입으로 바꾸면 문제가 되는 코드에서 정상적으로 에러가 발생한다.
let foo: unknown = 10; // Since `foo` has type `unknown`, TypeScript // errors on each of these usages. foo.x.prop; foo.y.prop; foo.z.prop; foo(); new foo(); upperCase(foo); foo `hello world!`; function upperCase(x: string) { return x.toUpperCase(); }
TypeScript
source of code: microsoft dev blogs, RC announcement
만약 unknown 타입의 변수를 사용할 때는 아래 코드처럼 타입 가드를 해야한다.
let foo: unknown = 10; function hasXYZ(obj: any): obj is { x: any, y: any, z: any } { return !!obj && typeof obj === "object" && "x" in obj && "y" in obj && "z" in obj; } // Using a user-defined type guard... if (hasXYZ(foo)) { // ...we're allowed to access certain properties again. foo.x.prop; foo.y.prop; foo.z.prop; } // We can also just convince TypeScript we know what we're doing // by using a type assertion. upperCase(foo as string); function upperCase(x: string) { return x.toUpperCase(); }
TypeScript
source of code: microsoft dev blogs, RC announcement
이외에도 unknown 타입의 특징을 살펴보고 싶다면 PR을 직접 확인해도 좋다.
&로 type을 intersection할 때 unknown은 다른 타입에 흡수되고, |로 type을 union하면 unknown이 다른 타입을 흡수하는 등, 여러 특징들이 나열되어 있다.

references