LE
A
PLAY
GaME
@phenomnomnominal 2022
@phenomnomnominal 2022
Sign
here
in
@phenomnomnominal 2022
HELLO!?
@phenomnomnominal 2022
What's going on?
@phenomnomnominal 2022
I'm CrAig
@phenomnomnominal 2022
@phenomnomnominal 2022
&
ex
in
type A
te
nd
s
fer
= B ?
C :
D
@phenomnomnominal 2022
@phenomnomnominal 2022
UnKno
inter
wn
face
ty
class
number
null
|
pe
@phenomnomnominal 2022
string
Date
boolean
Thingie
@phenomnomnominal 2022
const name: string = 'Craig';
Cannot Assign String to Number
const isKidnapped: boolean = true;
const timeRemaining: string = 18;
@phenomnomnominal 2022
const name: string = 'Craig';
CAN ASSIGN ANYTHING TO ANY
const isKidnapped: boolean = true;
const timeRemaining: any = 18;
@phenomnomnominal 2022
any
ANY IS A
TOP TYPE
string
Date
boolean
Thingie
@phenomnomnominal 2022
const isDead: boolean = true;
CAN ASSIGN ANYTHING TO unknown
const isAlive: boolean = false;
const timeRemaining: unknown = 18;
@phenomnomnominal 2022
any
string
Date
boolean
Thingie
Unknown IS Also A
TOP TYPE
unknown
@phenomnomnominal 2022
any
never
unknown
@phenomnomnominal 2022
Can't Assign anything to never
const nada: never = true;
const nope: never = null;
const nothing: never = 'Eighteen';
const nej: never = [];
const nein: never = () => ({});
@phenomnomnominal 2022
any
never
Never IS THE
Bottom TYPE
unknown
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
We got it!
@phenomnomnominal 2022
@phenomnomnominal 2022
asserts
PASS =
input
is
PASS
`${string}
_${string}`
in
string
|
number
|
Null
=
@phenomnomnominal 2022
@phenomnomnominal 2022
never
any
unknown
@phenomnomnominal 2022
const input: unknown = 'HELP';
function shout (input: string): string {
return `${input}!`;
}
shout(input);
Can't Assign unknown to string
@phenomnomnominal 2022
string
unknown
@phenomnomnominal 2022
if (typeof input === 'string') {
}
shout(input);
Input is definitely a string
const input: unknown = 'HELP';
function shout (input: string): string {
return `${input}!`;
}
@phenomnomnominal 2022
string
"HELP" | "PLEASE" | "SAVE US"
@phenomnomnominal 2022
function isHelp (input: unknown): input is Help {
const HELPS = ['HELP', 'PLEASE', 'SAVE US'];
return HELPS.includes(input as Help);
}
SPecial Type Guard Syntax
type Help = 'HELP' | 'PLEASE' | 'SAVE US';
@phenomnomnominal 2022
Input is definitely a valid string
if (isHelp(input)) {
shout(input);
}
const input: unknown = 'HELP';
type Help = 'HELP' | 'PLEASE' | 'SAVE US';
function isHelp (input: unknown): input is Help {
const HELPS = ['HELP', 'PLEASE', 'SAVE US'];
return HELPS.includes(input as Help);
}
@phenomnomnominal 2022
string
`${string}!`
@phenomnomnominal 2022
type Exclamation = `${string}!`;
special assertion guard syntax
function validate (input: unknown): {
if (typeof input !== 'string' || !input.endsWith('!')) {
throw new Error();
}
}
asserts input is Exclamation
@phenomnomnominal 2022
Input is definitely an Exclamation
validate(input);
shout(input);
type Exclamation = `${string}!`;
const input: unknown = 'HELP!';
function validate (input: unknown): asserts input is Exclamation {
if (typeof input !== 'string' || !input.endsWith('!')) {
throw new Error();
}
}
@phenomnomnominal 2022
type Scream = Uppercase<Exclamation>;
type GoodPassword = `${Scream}_${Whisper}`;
type Whisper = Lowercase<Exclamation>;
'A!_a!' | 'AA!_a!' | 'AAA!_aaa!' | 'AAAA!_aaaa! | 'AAAAA!_aaaaa!' | 'AAAAAA!_aaaaaa!' | ...
type Exclamation = `${string}!`;
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
ty
prop
peof
in
key
erty
<>
of
[index: string]
@phenomnomnominal 2022
Array<Item>
Promise<Resolved>
Uppercase<`${string}!`>;
Intrinsic string manipulation type
@phenomnomnominal 2022
type VictimName = string;
type VictimNames = Array<string>
type Help = 'HELP' | 'PLEASE' | 'SAVE US'
type Exclamation = `${string}!`;
@phenomnomnominal 2022
const status = {
'Ana': 'ungrateful',
'Rhubarb': 'grateful',
'Chau': 'ungrateful',
'Jeff': 'ungrateful',
'Santosh': 'ungrateful',
'Sherry': 'ungrateful'
};
type VictimStatus = Record<string, string>;
@phenomnomnominal 2022
type VictimStatus = {
[key: VictimName]: string;
}
type MikeStatus = VictimStatus['Mike']; // string
@phenomnomnominal 2022
type MakeGrateful<Victims> = {
[Name in keyof Victims]: 'grateful'
}
type Grateful = MakeGrateful<VictimStatus>;
type CraigStatus = Grateful['Craig']; // 'grateful'
type VictimStatus = {
[key: VictimName]: string;
}
@phenomnomnominal 2022
typefunction MakeGrateful (input) {
}
This is imaginary syntax!
type output = {};
output[name] = 'grateful';
return output;
for (name in input) {
}
@phenomnomnominal 2022
type MakeMemorial<Victims> = {
[Name in keyof Victims as `❤️ ${Name}`]: Victims[Name]
}
const LAST_WORDS = {
'Kirk': 'Plz',
'Spivey': 'My god, what have I done?',
'Erik': 'Will I get brutally murdered?',
'Srashti': 'Why not 😁',
'Katerina': '🐈'
}
define the new property
Lookup the type with the original name
@phenomnomnominal 2022
typefunction MakeMemorial (input) {
}
Lookup the type with the original name
define the new property
= input[name];
for (name in input) {
}
type output = {};
output[`❤️${name}`]
return output;
@phenomnomnominal 2022
type Memorials = MakeMemorial<typeof LAST_WORDS>;
const LAST_WORDS = {
'Kirk': 'Plz',
'Spivey': 'My god, what have I done?',
'Erik': 'Will I get brutally murdered?',
'Srashti': 'Why not 😁',
'Katerina': '🐈'
} as const;
Use typeof to Get a type from a POJO
Use specific string types
@phenomnomnominal 2022
type Memorials = MakeMemorial<typeof LAST_WORDS>;
const LAST_WORDS = {
'Kirk': 'Plz',
'Spivey': 'My god, what have I done?',
'Erik': 'Will I get brutally murdered?',
'Srashti': 'Why not 😁',
'Katerina': '🐈'
} as const;
type KirkMemorial = Memorials['❤️ Kirk']; // 'Plz'
look up the type with the mapped key
type KirkMemorial = Memorials['Kirk'];
// Error: Property "Kirk" does not exist
@phenomnomnominal 2022
type MappedType<A> = {
[B in keyof A as C]: D
}
A: Input Type
B: Union of KEY names
C: Mapped Key
D: Mapped TYpe
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
_!#J?:>
_!#7?:>
_!#3?:>
_!#E?:>
in
A ext
fer
B ?
C :
D
ends
Para
meters
extends
@phenomnomnominal 2022
type A extends B ? C : D
@phenomnomnominal 2022
type ConditionalType<A> = A extends B ? C : D
B: Super type
A: Input Type
C: True type
D: False type
@phenomnomnominal 2022
type Open<Key> = Key extends Password
? true
: false;
type Password = `${string}!_${string}!`;
type Locked = Open<'ngconf'>; // false
type Unlocked = Open<'HELP!_ME!'>; // true
@phenomnomnominal 2022
typefunction Open (Key) {
if (Key extends Password) {
return true;
}
return false;
}
type Password = `${string}!_${string}!`;
@phenomnomnominal 2022
type Encoded = `_!#${string}?:>`;
type Detect<Code> = Code extends Encoded
? Code
: never;
@phenomnomnominal 2022
type Encoded = `_!#${string}?:>`;
type Decode<Code> =
Code extends `_!#${infer Info}?:>`
? Info
: never;
type Decoded = Decode<`_!#J?:>`>; // J
@phenomnomnominal 2022
_!#J?:>
_!#7?:>
_!#3?:>
_!#F?:>
_!#9?:>
_!#)?:>
_!#E?:>
_!#%?:>
@phenomnomnominal 2022
type Letter = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
type Decode<Input extends `_!#${Letter}?:>`> =
Input extends `_!#${infer Info}?:>`
? Info
: never;
type Bad = Decode<'_!#%?:>`>; // never
type Good = Decode<'_!#J?:>`>; // J
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
@phenomnomnominal 2022
The TypeScript Type System
Type Narrowing
Top and Bottom Types
Template Literal Types
Mapped Types
Conditional Types
Extracting data with Infer
@phenomnomnominal 2022
THE END!
@phenomnomnominal 2022
THANKS!
@phenomnominal
LETS PLAY A GAME
By Craig Spence
LETS PLAY A GAME
- 2,453