Created
June 21, 2023 17:39
-
-
Save skanev/471fd51586ad38ecf533e08e3ddee4ba to your computer and use it in GitHub Desktop.
Dev BG example code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
console.log('baba') | |
// 1. Literal types | |
{ | |
let meta: 'foo' = 'foo' | |
meta = 'foo' | |
// @ts-expect-error | |
meta = 'bar' | |
console.log(meta) | |
let answer: 42 = 42 | |
answer = 42 | |
// @ts-expect-error | |
answer = 1 | |
} | |
// 2. Union types | |
{ | |
type BaseColor = 'red' | 'green' | 'blue' | |
let color: BaseColor = 'red' | |
color = 'green' | |
// @ts-expect-error | |
color = 'brown' | |
type StringOrNumber = string | number | |
let thing: StringOrNumber = 'foo' | |
thing = 42 | |
// @ts-expect-error | |
thing = {what: 1} | |
type OptionalName = string | undefined | |
let name: OptionalName | |
name = 'foo' | |
name = undefined | |
console.log(color) | |
console.log(name) | |
} | |
// 3. Intersection types | |
{ | |
type Color = 'red' | 'green' | 'orange' | 'black' | 'crimson' | 'peach' | 'fuchsia' | 'olive' | |
type Fruit = 'apple' | 'pear' | 'orange' | 'tomato' | 'olive' | 'aubergine' | 'peach' | |
type Both = Color & Fruit | |
let what: Both = 'orange' | |
console.log(what) | |
} | |
// 4. Subtypes and supertypes | |
{ | |
{ | |
type A = {a: number} | |
type B = {a: number; b: number} | |
type C = {a: number; b: number; c: number} | |
const a = {a: 1} | |
const b = {a: 1, b: 2} | |
const c = {a: 1, b: 2, c: 3} | |
let thing: A = a | |
thing = b | |
thing = c | |
let another: B = b | |
another = c | |
} | |
{ | |
type A = 'foo' | 'bar' | 'baz' | |
type B = 'foo' | 'bar' | |
type C = 'foo' | |
let a: A = 'foo' | |
a = 'bar' | |
a = 'baz' | |
let b: B = 'bar' | |
b = 'foo' | |
// @ts-expect-error | |
b = 'baz' | |
} | |
} | |
// 5. Covariance and contravariance | |
{ | |
type A = {a: number} | |
type B = {a: number; b: number} | |
type C = {a: number; b: number; c: number} | |
const a = {a: 1} | |
const b = {a: 1, b: 2} | |
const c = {a: 1, b: 2, c: 3} | |
function takesB(b: B) {} | |
takesB(b) | |
takesB(c) | |
// @ts-expect-error | |
takesB(a) | |
function returnsB() { | |
return b | |
} | |
const a2: A = returnsB() | |
const b2: B = returnsB() | |
// @ts-expect-error | |
const c2: C = returnsB() | |
function something(fn: (b: B) => B) {} | |
something((a: A) => b) | |
something((b: B) => b) | |
// @ts-expect-error | |
something((c: C) => b) | |
something((b: B) => b) | |
something((b: B) => c) | |
// @ts-expect-error | |
something((b: B) => a) | |
type User = {id: number; name: string} | |
type Admin = {id: number; name: string; owner: boolean} | |
function withUser(id: number, callback: (user: User) => void) { | |
callback({id, name: 'Rando'}) | |
} | |
function printUser(user: User) { | |
console.log(`User ${user.name} with id = ${user.id}`) | |
} | |
function printRecord(object: {id: number}) { | |
console.log(`Record with id = ${object.id}`) | |
} | |
withUser(1, printUser) | |
withUser(4, printRecord) | |
} | |
// 6. Literal checking | |
{ | |
type A = {one: number} | |
type B = {one: number; two: number} | |
type C = {one: number; two: number; three: number} | |
const a: A = {one: 1} | |
const b: B = {one: 1, two: 2} | |
const c: C = {one: 1, two: 2, three: 3} | |
function printB(object: B) { | |
console.log(`one = ${object.one}, two = ${object.two}`) | |
} | |
printB(b) | |
printB(c) | |
// @ts-expect-error | |
printB(a) | |
// @ts-expect-error | |
printB({one: 1, two: 2, three: 3}) | |
} | |
// 7. Indexing types | |
{ | |
type RepositoryResponse = { | |
id: number | |
url: string | |
owner: { | |
login: string | |
name: string | null | |
} | |
pullRequests: { | |
title: string | |
number: number | |
body: string | |
author: { | |
login: string | |
name: string | null | |
id: number | |
avatarUrl?: string | |
} | |
}[] | |
tags: { | |
name: string | |
id: number | |
}[] | |
} | |
const repository: RepositoryResponse = { | |
id: 1, | |
url: 'http://example.com/repo', | |
owner: { | |
login: 'baba', | |
name: 'Keanu Reeves' | |
}, | |
pullRequests: [ | |
{ | |
title: 'f1rs7 p0st', | |
author: { | |
id: 2, | |
name: null, | |
login: 'requester' | |
}, | |
body: '', | |
number: 1 | |
}, | |
{ | |
title: 'second change', | |
author: { | |
id: 4, | |
name: 'Keanu Reeves', | |
login: 'baba', | |
avatarUrl: 'http://example.com/baba.png' | |
}, | |
body: '', | |
number: 1 | |
} | |
], | |
tags: [ | |
{name: 'cool', id: 1}, | |
{name: 'sweet', id: 2} | |
] | |
} | |
function authorTile(author: {login: string; name: string | null}) { | |
console.log(`Tile of user ${author.login} (${author.name ?? '–'})`) | |
} | |
} | |
// 8. Discriminated Union Types | |
{ | |
type Shape = | |
| {kind: 'circle'; radius: number} | |
| {kind: 'square'; side: number} | |
| {kind: 'triangle'; a: number; b: number; c: number} | |
function shapeInfo(shape: Shape): string { | |
switch (shape.kind) { | |
case 'circle': | |
return `Circle with radius ${shape.radius}` | |
case 'square': | |
return `Square with side ${shape.side}` | |
case 'triangle': | |
return `Triangle with sides ${shape.a}, ${shape.b}, ${shape.c}` | |
} | |
} | |
} | |
// 9. Exhaustiveness cheking for union types (shapes) | |
{ | |
type Shape = | |
| {kind: 'circle'; radius: number} | |
| {kind: 'square'; side: number} | |
| {kind: 'triangle'; a: number; b: number; c: number} | |
// | {kind: 'rectangle'; a: number; b: number} | |
function checkExhausted(value: never): never { | |
throw `Unexpected value: ${value}` | |
} | |
function printShape(shape: Shape) { | |
switch (shape.kind) { | |
case 'circle': | |
console.log(`Circle with radius ${shape.radius}`) | |
return | |
case 'square': | |
console.log(`Square with side ${shape.side}`) | |
return | |
case 'triangle': | |
console.log(`Triangle with sides ${shape.a}, ${shape.b}, ${shape.c}`) | |
return | |
default: | |
checkExhausted(shape) | |
} | |
} | |
} | |
// 10. Precondition checking for union types (statuses) | |
{ | |
type Payload<Data> = | |
| {status: 'loading'} | |
| {status: 'error'; error: string; statusCode: number} | |
| {status: 'success'; data: Data; responseTime: number} | |
type PullRequest = { | |
id: number | |
title: string | |
} | |
function usePullRequest(id: number): Payload<PullRequest> { | |
return null as any | |
} | |
function PullRequest(id: number) { | |
const payload = usePullRequest(1) | |
if (payload.status === 'loading') { | |
return 'Loading...' | |
} else if (payload.status === 'error') { | |
return 'Error...' | |
} | |
return PullRequestTile2(payload) | |
} | |
function precondition(value: unknown): asserts value { | |
if (!value) { | |
throw 'precondition failed' | |
} | |
} | |
function PullRequestTile(payload: Payload<PullRequest>) { | |
precondition(payload.status === 'success') | |
// if (payload.status !== 'success') { | |
// throw 'unreachable' | |
// } | |
return `We've got a pull request: ${payload.data.title} (took: ${payload.responseTime}ms)` | |
} | |
function PullRequestTile2(payload: Payload<PullRequest> & {status: 'success'}) { | |
// if (payload.status !== 'success') { | |
// throw 'unreachable' | |
// } | |
return `We've got a pull request: ${payload.data.title} (took: ${payload.responseTime}ms)` | |
} | |
} | |
// 11. Utility types | |
{ | |
// Partial and Required | |
type User = { | |
id: number | |
name: string | |
email: string | |
city: string | null | |
} | |
type Baba = Record<string, string> | |
function update<Payload>(id: number, update: Payload) {} | |
// @ts-expect-error | |
update<User>(1, {name: 'Baba'}) | |
// Omit, Exclude, | |
// Record | |
type Shape = | |
| {kind: 'circle'; radius: number} | |
| {kind: 'square'; side: number} | |
| {kind: 'triangle'; a: number; b: number; c: number} | |
// | {kind: 'rectangle'; a: number; b: number;} | |
const shapeDescriptions = { | |
square: 'A figure with four sides that are equal', | |
circle: 'A round thing', | |
triagnle: 'A figure with three sides' | |
} | |
// ReturnType | |
function fetchPage(): {body: string; statusCode: number; responseTime: number} { | |
return null as any | |
} | |
} | |
// 12. Implementing Partial | |
{ | |
type User = { | |
id: number | |
name: string | |
email: string | |
city: string | null | |
} | |
type MyPartial<T> = {[K in keyof T]?: T[K]} | |
type PartialUser = MyPartial<User> | |
} | |
// 13. Field on a form (just has the field) | |
{ | |
type User = { | |
height: number | |
name: string | |
email: string | |
city: string | null | |
age: number | |
} | |
const user: User = { | |
height: 180, | |
age: 33, | |
city: 'Jerusaleam', | |
email: '[email protected]', | |
name: 'John Doe' | |
} | |
function textField<Payload>(payload: Payload, field: string) {} | |
textField(user, 'name') | |
textField(user, 'age') | |
textField(user, 'whatever') | |
} | |
// 14. String fields on form | |
{ | |
type User = { | |
height: number | |
name: string | |
email: string | |
city: string | null | |
age: number | |
} | |
const user: User = { | |
height: 180, | |
age: 33, | |
city: 'Jerusaleam', | |
email: '[email protected]', | |
name: 'John Doe' | |
} | |
type StringFields<T> = { | |
[K in keyof T]: T[K] extends string ? K : never | |
}[keyof T] | |
type Test = StringFields<User> | |
function textField<Payload>(payload: Payload, field: StringFields<Payload>) {} | |
textField(user, 'name') | |
// @ts-expect-error | |
textField(user, 'city') | |
// @ts-expect-error | |
textField(user, 'whatever') | |
} | |
// 15. Decimal field with some generalisation | |
// 14. String fields on form | |
{ | |
type User = { | |
height: number | |
name: string | |
email: string | |
city: string | null | |
age: number | |
} | |
const user: User = { | |
height: 180, | |
age: 33, | |
city: 'Jerusaleam', | |
email: '[email protected]', | |
name: 'John Doe' | |
} | |
type PropertiesOfSubtype<T, V> = { | |
[K in keyof T]: T[K] extends V ? K : never | |
}[keyof T] | |
function textField<Payload>(payload: Payload, field: PropertiesOfSubtype<Payload, string>) { | |
const what = payload[field] | |
} | |
textField(user, 'name') | |
textField(user, 'email') | |
// @ts-expect-error | |
textField(user, 'height') | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment