如何为可区分的联合创建通用组合函数
How to create generic composing functions for discriminated unions
我可能正在尝试使用 TypeScript 系统的限制,但是是否可以通过组合 isA
来正确定义 makeIsBox
来创建 isBoxA
?
type A = 'A'
type B = 'B'
type Letter = A | B
const makeIsLetter = <L extends Letter>(checkLetter: L) => (letter: Letter): letter is L => letter === checkLetter
const isA = makeIsLetter('A')
const isB = makeIsLetter('B')
// Test
const takeA = (a: A) => void 0
const takeB = (b: B) => void 0
declare const a: Letter
declare const b: Letter
takeA(a) // should fail
if(isA(a)) {
takeA(a) // should not fail
} else {
takeA(a) // should fail
takeB(a) // should not fail>
}
// So far so good.
type BoxA = { type: A, value: string }
type BoxB = { type: B, status: number }
type Box = BoxA | BoxB
const makeIsBox = <
L extends Letter,
Fn extends (letter: Letter) => letter is L
>(
fn: Fn
) => <B extends Box>(box: Box) => fn(box.type)
const isBoxA = makeIsBox(isA)
declare const box: Box
if (isBoxA(box)) {
const value = box.value
}
TypeScript 不会 infer a user-defined type guard 适合你。你必须自己注释它,像这样:
const makeIsBox = <L extends Letter>(fn: (letter: Letter) => letter is L) => (
box: Box
): box is Extract<Box, { type: L }> => fn(box.type);
这仍然只需要在 L
中是通用的。它接受类型 (l: Letter)=>l is L
的函数和 returns 类型 (b: Box)=>b is Extract<Box, {type: L}>
的函数。那就是使用 Extract
utility type 到 select 只是 Box
联盟的成员,它可以分配给 {type: L}
。
它应该按照你想要的方式工作:
const isBoxA = makeIsBox(isA);
declare const box: Box;
if (isBoxA(box)) {
const value = box.value;
} else {
const status = box.status;
}
希望对您有所帮助;祝你好运!
我可能正在尝试使用 TypeScript 系统的限制,但是是否可以通过组合 isA
来正确定义 makeIsBox
来创建 isBoxA
?
type A = 'A'
type B = 'B'
type Letter = A | B
const makeIsLetter = <L extends Letter>(checkLetter: L) => (letter: Letter): letter is L => letter === checkLetter
const isA = makeIsLetter('A')
const isB = makeIsLetter('B')
// Test
const takeA = (a: A) => void 0
const takeB = (b: B) => void 0
declare const a: Letter
declare const b: Letter
takeA(a) // should fail
if(isA(a)) {
takeA(a) // should not fail
} else {
takeA(a) // should fail
takeB(a) // should not fail>
}
// So far so good.
type BoxA = { type: A, value: string }
type BoxB = { type: B, status: number }
type Box = BoxA | BoxB
const makeIsBox = <
L extends Letter,
Fn extends (letter: Letter) => letter is L
>(
fn: Fn
) => <B extends Box>(box: Box) => fn(box.type)
const isBoxA = makeIsBox(isA)
declare const box: Box
if (isBoxA(box)) {
const value = box.value
}
TypeScript 不会 infer a user-defined type guard 适合你。你必须自己注释它,像这样:
const makeIsBox = <L extends Letter>(fn: (letter: Letter) => letter is L) => (
box: Box
): box is Extract<Box, { type: L }> => fn(box.type);
这仍然只需要在 L
中是通用的。它接受类型 (l: Letter)=>l is L
的函数和 returns 类型 (b: Box)=>b is Extract<Box, {type: L}>
的函数。那就是使用 Extract
utility type 到 select 只是 Box
联盟的成员,它可以分配给 {type: L}
。
它应该按照你想要的方式工作:
const isBoxA = makeIsBox(isA);
declare const box: Box;
if (isBoxA(box)) {
const value = box.value;
} else {
const status = box.status;
}
希望对您有所帮助;祝你好运!