preface

There are two top-level types of TS, any and unknown, which are so similar that in everyday use it is difficult to define when to use any and when to use unknown. This article is about that.

any

Any type can be assigned to any, which is the escape pod for TS type checks and tells TSC to skip type checks directly. Any defeats the purpose of type checking and is generally not recommended, especially if unknown types exist.

unknown

Typescript3.0 introduces unknown, which can be understood as a type-safe version of any. Similarly, any type can be assigned to unknown, but unknown cannot be assigned to any type other than unknown or any without type assertion or type narrowing.

contrast

  1. Any type can be assigned toanyandunknown.anyCan be assigned to any type,unknownCan only be assigned tounknownorany.
// Any type can be assigned to any
function f01<T> (pAny: any, pNever: never, pT: T) {
  let x: any;
  x = 123;
  x = "hello";
  x = [1.2.3];
  x = new Error(a); x = x; x = pAny; x = pNever; x = pT; }// Any can be assigned to any type
function f02<T> (x: any) {
  let v1: any = x;
  let v2: unknown = x;
  let v3: object = x;
  let v4: string = x;
  let v5: string[] = x;
  let v6: {} = x;
  let v7: {} | null | undefined = x;
}
// Any type can be assigned 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(a); x = x; x = pAny; x = pNever; x = pT; }// Unknown can only be assigned to unknown or 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
  let v8: string = x as string; // Ok, assert string
}
function f23(x: unknown) :string {
  if (typeof x === 'string') {
    return x; // Ok
  }
  return String(x);
}
Copy the code
  1. anyWith any typeTThe crossover type ofany.unknownWith any typeTThe crossover type ofT, i.e.,

any & T => any unknown & T => T

Any & never => never, unknown & never => never, unknown & any => any

type T00 = any & null; // any
type T01 = any & undefined; // any
type T02 = any & null & undefined; // never
type T03 = any & string; // any
type T04 = any & string[]; // any
type T05 = any & unknown; // any
type T06 = any & any; // any

type T10 = unknown & null; // null
type T11 = unknown & undefined; // undefined
type T12 = unknown & null & undefined; // null & undefined (which becomes never)
type T13 = unknown & string; // string
type T14 = unknown & string[]; // string[]
type T15 = unknown & unknown; // unknown
type T16 = unknown & any; // any
Copy the code
  1. anyWith any typeTIs the union type ofany.unknownWith any typeTIs the union type ofunknown, i.e.,

any | T => any unknown | T => unknown

Unknown is the same as any, but any has a higher priority.

type T00 = any | null; // any
type T01 = any | undefined; // any
type T02 = any | null | undefined; // any
type T03 = any | string; // any
type T04 = any | string[]; // any
type T05 = any | unknown; // any
type T07 = any | never; // any

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 T16 = unknown | any; // any
type T17 = unknown | never; // unknown
Copy the code
  1. anyTypes can be attribute access, element access, function calls,unknownNot when there is no type narrowing
function f10(x: any) {
  x.foo; // OK
  x[5]; // OK
  x(); // OK
  new x(); // OK
}
function f11(x: unknown) {
  x.foo; // Error
  x[5]; // Error
  x(); // Error
  new x(); // Error
}
Copy the code
  1. anyYou can use any operator and operator,unknownIt can only be judged by equivalence
function f10(x: any) {
  x == 5; x ! = =10;
  x >= 0;
  x + 1;
  x * 2;
  -x;
  +x;
}
function f11(x: unknown) {
  x == 5; x ! = =10;
  x >= 0; // Error
  x + 1; // Error
  x * 2; // Error
  -x; // Error
  +x; // Error
}
Copy the code
  1. keyofThe different
type T00 = keyof any; // string | number | symbol
type T01 = keyof unknown; // never
Copy the code
  1. Homomorphic mappings
type T10<T> = { [P in keyof T]: number };
type T11 = T10<any>; // { [x: string]: number }
type T12 = T10<unknown>; / / {}
Copy the code
  1. Function returns differently. The function returns a value of typeanyCan have no return statement, but isunknownWhen you have.
function f10() :any {} // OK
function f11() :unknown {} // Error
Copy the code

Except in the above cases, unknown and any behave basically the same.

The resources

  1. www.typescriptlang.org/docs/handbo…
  2. Thesoftwaresimpleton.com/blog/2019/0…
  3. Fullstackbb.com/typescript/…