Я пытаюсь реализовать своего рода сопоставление псевдо-шаблонов в Typescript, используя их поддержку для распознаваемых объединений, используя функцию соответствия вместе с объектом, представляющим ветви выражения соответствия.
ВотСценарий, который я хотел бы использовать:
type Shape =
| { kind: 'Circle', radius: number }
| { kind: 'Rectangle', height: number, width: number }
function printShape(s: Shape) {
return document.write(
match(s, {
'Circle': c => `Circle(${c.radius})`,
'Rectangle': r => `Rectangle(${r.width} x ${r.height})`
}));
}
Моя текущая попытка определения функции соответствия выглядит следующим образом:
function match<T extends { kind: V }, V extends string, R>(
x: T, branches: { [P in T['kind']]: (arg: T & { 'kind': P }) => R }) {
return branches[x.kind](x);
}
Это близко, но, к сожалению, не 'т совсем работа;в то время как я успешно получил компилятор, чтобы жаловаться на полноту для заданных совпадений, аргументы для функций ветвления не очень хорошо типизированы: аргументы c
и r
имеют тип any
.
IЯ согласен с наличием kind
в качестве жестко заданного дискриминатора, но я обычно не понимаю в Typescript, как отфильтровывать возможности из универсального объединения типов.Например, я сосредоточил свое упражнение на попытке написать следующее:
type Where<T, K extends keyof T, V extends T[K]> = ???
У меня правильные ограничения типов в том, что я получаю правильную проверку моих типов и литералов от компилятора при написании:
type Circle = Where<Shape, 'kind', 'Circle'>
но я не понимаю, что я могу написать справа от этого выражения типа, чтобы вернуть:
{ kind: 'Circle', radius: number }