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,649