Тайп-фу в TS

Oct 17, 2021 10:30

У нас тут есть сторонний HTTP-сервис, возвращающий либо { success: true } либо { error: 42, description: "because" }. Ну и по openapi.yaml генерится в таком духе декларация (за правильность кейвордов не ручаюсь):

export interface Foo {
bar:
| { success: boolean }
| { error: number, description: string }
}Ну и есть такой вот код:

const foo: Foo = getFoo()

if ('error' in foo) {
throw new Error(foo.description)
}

console.log(foo.success)Ну и это работает как GADT pattern matching, только без гадтов и паттернов :) То есть внутри ифа нельзя напечатать foo.success - будет ошибка компиляции, а после ифа нельзя доступиться к error или description, поскольку компилятор видит, что мы сделали достаточно рантайм-сравнений для сужения типа foo в разных участках кода до одной ветки (то, что throw обрывает control flow - он тоже видит).

И тут интересно, ввиду того что спецификация кросс-языковая, как с этой ситуацией (типизированная работа с вариантами ответа) предлагает справляться OpenAPI/Swagger кодогенерация для других языков.

Там кстати есть тонкости в схеме, что надо лепить
additionalProperties: false
required:
- success, иначе мы говорим, что все поля нуллабле и он генерит не то, что мы имеем ввиду.

Ну и это конечно непонятно как на наших гребцов ляжет. Разрешу им везде as unknown as any писать чтобы батька потом чинил :)

fp, все пидарасы а я, programming

Previous post Next post
Up