条件类型未正确推断

时间:2019-01-28 22:57:27

标签: typescript

在此示例TypeScript代码中,我声明了一个具有conditional return type的函数。

/**
 * Do all elements of `a` appear in `b` and in the same order?
 */
declare function isSubarrayOf<T, U>(
    a: ReadonlyArray<T>,
    b: ReadonlyArray<U>
): T extends U ? boolean : false;

如果数组a可能是数组b的子数组,则键入T 必须分配为类型U,因此函数返回boolean。相反,如果T不扩展U,则没有办法 a可能是b的子数组,因此该函数必须返回false

我尝试在此测试中获得false,但仍被推断为boolean

let a: number[] = [1, 2, 3]
let b: (string | number)[] = [1, 2, '3']

let test1: boolean = isSubarrayOf(a, b)
let test2: false = isSubarrayOf(b, a) // unexpected error!

/*
 * WAT?
 * `b` could never be a subarray of `a`,
 * since `string|number` is not assignable to `number`,
 * so the type of `test2` should be `false`.
 * however, the inferred type is boolean???
 */

所以我做了一些更多的测试,以确保我不会发疯,但是这些测试都通过了。

/*
 * testing: is `string|number` assignable to `number`?
 * if yes, `x` should be assignable to `y`.
 * if no, should get an error.
 */
let x: string | number = 'x'
let y: number = x // expected error

/*
 * testing: does `(string | number) extends number`?
 * if yes, `test3` should be `boolean`, assigned true.
 * if no, should be `false`, should get an error.
 */
let test3: (string | number) extends number ? boolean : false
    = true // expected error

我错过了什么吗?或者这是一个错误?

Playground link

1 个答案:

答案 0 :(得分:2)

我相信您真正想要的是:

declare function isSubarrayOf<T, U>(
    a: ReadonlyArray<T>,
    b: ReadonlyArray<U>
): [T] extends [U] ? boolean : false;

请注意[T][U]周围的方括号。该语法告诉TypeScript不要在联合类型上分配,这在使用条件类型时会发生。参见distributive conditional types

进行此更改后,您的函数将如下所示:

isSubarrayOf([1], [1])        // potentially true (the type is the same)
isSubarrayOf([1], ['1'])      // false (they have nothing in common)
isSubarrayOf(['1'], [1])      // false (they have nothing in common)

isSubarrayOf(['1'], [1, '1']) // potentially true (first is more narrow than the second)
isSubarrayOf(['1', 1], [1])   // false (first is wider)