Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Diagram of every possible TypeScript type

Hasse diagram of every possible TypeScript type

  • any: magic, ill-behaved type that acts like a combination of never (the proper bottom type) and unknown (the proper top type)
    • Anything except never is assignable to any, and any is assignable to anything at all.
    • Identities: any & AnyTypeExpression = any, any | AnyTypeExpression = any
    • Key TypeScript feature that allows for gradual typing.
  • unknown: proper, well-behaved top type
    • Anything at all is assignable to unknown. unknown is only assignable to itself (unknown) and any.
    • Identities: unknown & AnyTypeExpression = AnyTypeExpression, unknown | AnyTypeExpression = unknown
    • Prefer over any whenever possible. Anywhere in well-typed code you're tempted to use any, you probably want unknown.
    • Equivalent to {} | null | undefined.
  • never: proper, well-behaved bottom type
    • Nothing besides itself (never) is assignable to never, but never is assignable to anything at all.
    • Identities: never & AnyTypeExpression = never, never | AnyTypeExpression = AnyTypeExpression
    • You'll see it in error messages related to exceptions and exhaustiveness checking, but you'll rarely write it outside of conditional types, where it's useful for "negating" a condition.
  • null: the only proper unit type, though there are two other unit-like types
    • Nothing besides itself (null), never, and any are assignable to null. null is assignable to itself (null)
  • undefined: unit-like type. Not quite a proper unit type because it's assignable to void (unit types are normally only assignable to themselves and the top type)
    • Nothing besides itself (undefined), never, and any are assignable to undefined. undefined is only assignable to void and, as always, itself (undefined), unknown, and any.
  • void: irregular [unit-like type]. Not a proper unit type because undefined is assignable to it (normally nothing is assignable to a unit type except itself and the bottom type)
    • Besides itself (void), never, and any, only undefined is assignable to void.void is only assignable to itself (void), unknown, and any.
    • Irregular because the set of values in this type is equal to the set of values that the undefined type consists of, specifically, the JavaScript value undefined. Normally that would make them the same unit type rather than two distinct unit-like types.
    • Useful to distinguish functions whose return value you aren't supposed to use at all, from functions whose return value may be the value undefined. E.g. if you have foo: () => void and bar: (x?: string) => number, then bar(foo()) is a type error.
  • boolean, number, string, symbol: primitive types, all disjoint
    • All the primitive types are all disjoint from each other and from null, undefined, and object, which means none of them are assignable to each other. Only themselves and their literal types (and never and any) are assignable to them, that is:
      • Only true and false are assignable to boolean (in fact, boolean is equivalent to true | false).
      • Only number literal types like 0, 1, 42, -7, 3.14 are assignable to number.
      • Only string literal types like "", "asdf", "etc." are assignable to string.
      • There are no symbol literals, the only way to create symbols is the Symbol constructor.
    • Primitive types are assignable to any subtype of the corresponding interface, for example number, and any number literal type, is assignable to the interface Number, or any subtype such as the interface { toFixed(): string }.
      • This implies all 4 of these primitive types are assignable to {}.
  • interface types: { whatever: AnyTypeExpression }
    • Assignable to subtypes like { a: number, b: string } is assignable to { a: number }, and { a: number } is assignable to { readonly a: number } or { a?: number } or { [prop: string]: number }.
    • There are many built-in interface types, like Object, Number, Date, RegExp, Array, ReadonlyArray, etc.
      • Object, {}, { toString(): string }, and all other subtypes of the Object interface are all the same type, thanks to the Object interface being a pseudo-top type.
      • Array<T> and ReadonlyArray<T> can also be written with the syntactic sugar T[] and readonly T[], respectively.
  • object: magic, but well-behaved refinement type, essentially {} but excluding the primitive types
    • Would be equivalent to Exclude<{}, boolean | number | string | symbol>, if Exclude<_,_> worked on interface types that aren't union types.
@yayajacky
Copy link

yayajacky commented Jan 10, 2020

Very nice

@frangio
Copy link

frangio commented Jan 14, 2020

foo() === undefined is a type error if foo() returns void

This doesn't seem to be true. Playground Link

@anka-213
Copy link

anka-213 commented Mar 17, 2020

Is it possible to assign an unknown value to a {} | null | undefined value since they are equivalent? How do you consume unknown values?

@nin-jin
Copy link

nin-jin commented Apr 5, 2020

image

@fhpriamo
Copy link

fhpriamo commented May 25, 2020

Dude, that's amazing. Thank you.

@SerkanSipahi
Copy link

SerkanSipahi commented Jan 4, 2021

Thanks 👍

@laughinghan
Copy link
Author

laughinghan commented Jan 12, 2021

@anka-213 You're right—and more generally, an equality check between a subtype and supertype are always allowed, duh

@laughinghan
Copy link
Author

laughinghan commented Jan 12, 2021

Another mistake: there's actually no Infinity or NaN number literal type, because NaN is an ill-behaved value, so you can't type-narrow with ===. (There seems to be no good reason for the lack of an Infinity literal type.) microsoft/TypeScript#28682

Also, omissions, which I haven't fixed:

@tjjfvi
Copy link

tjjfvi commented Feb 5, 2021

Nothing besides itself (never) and any are assignable to never, but never is assignable to anything at all.

any is not assignable to never

@laughinghan
Copy link
Author

laughinghan commented Feb 11, 2021

@tjjfvi Oh damn, you're right! Fixed the text, haven't fixed the diagram because I don't have the original editable version, I don't even remember how I made it lol

Also how are you all even finding this?

@tjjfvi
Copy link

tjjfvi commented Feb 11, 2021

@laughinghan I was linked to it on the typescript discord, but this gist is the top google result for "typescript type diagram".

@whoisYeshua
Copy link

whoisYeshua commented Oct 5, 2021

@tjjfvi Oh damn, you're right! Fixed the text, haven't fixed the diagram because I don't have the original editable version, I don't even remember how I made it lol

Also how are you all even finding this?

So, I think we need to fix this part as well:

Anything except never is assignable to "any", and "any" is assignable to anything at all.

to:

Anything is assignable to "any", and "any" is assignable to anything at all (except never).

declare const any: any;
const never: never = any; // Error
declare const never2: never
const any2: any = never // Ok

@whoisYeshua
Copy link

whoisYeshua commented Oct 5, 2021

TS_types_fixed-removebg

@workjacinjiyan
Copy link

workjacinjiyan commented Apr 22, 2022

TS_types_fixed-removebg

I am guessing this is the most accurate one

@nin-jin
Copy link

nin-jin commented Apr 22, 2022

type A = never extends any ? 1 : 2 // 1
type B = any extends never ? 1 : 2 // 1 | 2

Any is a jocker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment