Skip to content

Instantly share code, notes, and snippets.

@skanev
Created June 21, 2023 17:39
Show Gist options
  • Save skanev/471fd51586ad38ecf533e08e3ddee4ba to your computer and use it in GitHub Desktop.
Save skanev/471fd51586ad38ecf533e08e3ddee4ba to your computer and use it in GitHub Desktop.
Dev BG example code
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