我的代码如下:
/** explains the absence of a value */
export interface None {
'is none because': string;
// has spaces to reduce likelihood of a non-None having this member
}
/** Either a value or a reason why that value is missing. */
export type Optional<a> = a | None;
/** Possible value actually is a value */
export function isSome<a>(optValue: Optional<a>): optValue is a {
return !('is none because' in optValue);
}
/** Possible value actually is absent */
export function isNone<a>(optValue: Optional<a>): optValue is None {
return 'is none because' in optValue;
}
/** Consider optional value, require users to consider both possibilities */
export function outOfOptional<a, r>(value: Optional<a>, haveSome: (some: a) => r, haveNone: (reason: string) => r): r {
if (isNone(value)) {
return haveNone(value['is none because']);
}
else {
return haveSome(value);
}
}
但是,我发现这个设置存在两个问题。两者都与在这些效用函数中自动推导泛型类型有关。
首先,isSome
似乎不能作为打字机使用:
if (isSome(value)) {
// value here is still treated as a | None
}
这里的默认扣除似乎是isSome<Optional<a>>
,这显然是错误的(isSome<Optional<a>>
应该期待Optional<Optional<a>>
的论证,这不是它在这里得到的)。如果我明确并使用isSome<a>
,那么它可行,但我绝对不想这样做。
或者,isNone
确实有效,这就是您在outOfOptional
中看到它的原因:value
在a
块中有else
类型。
此外,请考虑outOfOptional
的使用情况:
export function outOfBothOptional<a, b, r>(
one: Optional<a>, another: Optional<b>,
haveBoth: (one: a, another: b) => r,
haveFirst: (one: a) => r,
haveSecond: (another: b) => r,
haveNone: (none: string) => r
): r {
return outOfOptional(
one,
haveOne => outOfOptional(
another,
haveAnother => haveBoth(haveOne, haveAnother),
() => haveFirst(haveOne)
),
() => outOfOptional(
another,
haveSecond,
haveNone
)
);
}
haveOne
和haveAnother
推导为a | None
而不是a
,即使这会导致错误,即使他们也不能。实际上,此处的outOfOptional
似乎被视为outOfOptional<Optional<a>>
,除了错误之外,原因相同isSome<Optional<a>>
错误。第一个参数是Optional<a>
,而不是Optional<a> | None
或Optional<Optional<a>>
,因为扣除意味着。鉴于Optional<a>
的第一个参数,outOfOptional
的泛型类型必须为a
,绝对不是Optional<a>
。
为什么TypeScript认为这是有效的,实际上更有效,扣除?无论如何我可以使用a | None
作为可选类型,而不必在相关函数中明确指出泛型类型吗?
答案 0 :(得分:2)
你认为这应该是可以推断的直觉是正确的,事实上当前每晚的TypeScript版本(npm install typescript@next
)确实推断出正确的类型。
查看修正此https://github.com/Microsoft/TypeScript/pull/5895的PR和原始错误https://github.com/Microsoft/TypeScript/issues/5861