any
: magic, ill-behaved type that acts like a combination ofnever
(the proper bottom type) andunknown
(the proper top type)- Anything except
never
is assignable toany
, andany
is assignable to anything at all. - Identities:
any & AnyTypeExpression = any
,any | AnyTypeExpression = any
- Key TypeScript feature that allows for gradual typing.
- Anything except
unknown
: proper, well-behaved top type- Anything at all is assignable to
unknown
.unknown
is only assignable to itself (unknown
) andany
. - Identities:
unknown & AnyTypeExpression = AnyTypeExpression
,unknown | AnyTypeExpression = unknown
- Prefer over
any
whenever possible. Anywhere in well-typed code you're tempted to useany
, you probably wantunknown
. - Equivalent to
{} | null | undefined
.
- Anything at all is assignable to
never
: proper, well-behaved bottom type- Nothing besides itself (
never
) is assignable tonever
, butnever
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.
- Nothing besides itself (
null
: the only proper unit type, though there are two other unit-like types- Nothing besides itself (
null
),never
, andany
are assignable tonull
.null
is assignable to itself (null
)
- Nothing besides itself (
undefined
: unit-like type. Not quite a proper unit type because it's assignable tovoid
(unit types are normally only assignable to themselves and the top type)- Nothing besides itself (
undefined
),never
, andany
are assignable toundefined
.undefined
is only assignable tovoid
and, as always, itself (undefined
),unknown
, andany
.
- Nothing besides itself (
void
: irregular [unit-like type]. Not a proper unit type becauseundefined
is assignable to it (normally nothing is assignable to a unit type except itself and the bottom type)- Besides itself (
void
),never
, andany
, onlyundefined
is assignable tovoid
.void
is only assignable to itself (void
),unknown
, andany
. - 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 valueundefined
. 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 havefoo: () => void
andbar: (x?: string) => number
, thenbar(foo())
is a type error.
- Besides itself (
boolean
,number
,string
,symbol
: primitive types, all disjoint- All the primitive types are all disjoint from each other and from
null
,undefined
, andobject
, which means none of them are assignable to each other. Only themselves and their literal types (andnever
andany
) are assignable to them, that is:- Only
true
andfalse
are assignable toboolean
(in fact,boolean
is equivalent totrue | false
). - Only number literal types like
0
,1
,42
,-7
,3.14
are assignable tonumber
. - Only string literal types like
""
,"asdf"
,"etc."
are assignable tostring
. - There are no symbol literals, the only way to create symbols is the
Symbol
constructor.
- Only
- Primitive types are assignable to any subtype of the corresponding interface, for example
number
, and any number literal type, is assignable to the interfaceNumber
, or any subtype such as the interface{ toFixed(): string }
.- This implies all 4 of these primitive types are assignable to
{}
.
- This implies all 4 of these primitive types are assignable to
- All the primitive types are all disjoint from each other and from
- 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 theObject
interface are all the same type, thanks to theObject
interface being a pseudo-top type.Array<T>
andReadonlyArray<T>
can also be written with the syntactic sugarT[]
andreadonly T[]
, respectively.
- Assignable to subtypes like
object
: magic, but well-behaved refinement type, essentially{}
but excluding the primitive types- Would be equivalent to
Exclude<{}, boolean | number | string | symbol>
, ifExclude<_,_>
worked on interface types that aren't union types.
- Would be equivalent to
-
-
Save laughinghan/31e02b3f3b79a4b1d58138beff1a2a89 to your computer and use it in GitHub Desktop.
Dude, that's amazing. Thank you.
Thanks 👍
@anka-213 You're right—and more generally, an equality check between a subtype and supertype are always allowed, duh
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:
- tuple types
- intersection and union types
- enum types, which I believe are equivalent to unions of string/number literal types
Nothing besides itself (
never
) andany
are assignable tonever
, butnever
is assignable to anything at all.
@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?
@laughinghan I was linked to it on the typescript discord, but this gist is the top google result for "typescript type diagram".
@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
type A = never extends any ? 1 : 2 // 1
type B = any extends never ? 1 : 2 // 1 | 2
Any is a jocker.
nice!
Is it possible to assign an
unknown
value to a{} | null | undefined
value since they are equivalent? How do you consumeunknown
values?