Typescript:排除<T, K> 不排除我的类型

Jos*_*ang 2 generics typescript

我构建了一个名为 的函数compact,该函数的作用是删除数组中的所有假值。

这是以下javascript的实现compact

function compact(arr) {
  return arr.filter(Boolean);
}

const MyData = [0, 1, null, 2, undefined, ''];

console.log(compact(MyData))
// => [1, 2]
Run Code Online (Sandbox Code Playgroud)

这是以下的Typescript 打字部分compact

function compact(arr) {
  return arr.filter(Boolean);
}

const MyData = [0, 1, null, 2, undefined, ''];

console.log(compact(MyData))
// => [1, 2]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在,奇怪的部分来了,当我将它与代码连接起来时compact,它实际上不起作用:

type Falsy = false | null | 0 | '' | undefined;

type Compact<T extends any[]> = Exclude<T[number], Falsy>;

// some correct test
type MyData = [0, 1, null, 2, undefined, ''];

type MyDataWithoutFalsy = Compact<MyData>
// => type MyDataWithoutFalsy = 1 | 2
Run Code Online (Sandbox Code Playgroud)

它应该是number唯一的,因为应该排除空字符串。

在此输入图像描述

Tit*_*mir 5

问题不在于Exclude,问题在于 for ""(不仅仅是对于这个字符串文字,对于任何字符串文字)打字稿通常不会保留字符串文字类型,而是会将其扩大到,string除非我们给它一个保留字符串文字的理由文字类型。

要向编译器提示您需要文字类型,必须将文字分配给受文字基类型约束的泛型类型参数:

function compact<V extends (string | undefined | boolean | object | number | null), T extends V[]>(arr: T & V[]): Compact<T> {
    return arr.filter(Boolean) as Compact<T>;
}

let MyDataWithoutFalsy = compact([0, 1, null, 2, undefined, '']); // number


type Falsy = false | null | 0 | '' | undefined;

type Compact<T extends any[]> = Exclude<T[number], Falsy>;
Run Code Online (Sandbox Code Playgroud)

请注意,这确实意味着compact除非您以保留文字类型(例如 )的方式构造数组,否则它不会真正可用''

function compact<V extends (string | undefined | boolean | object | number | null), T extends V[]>(arr: T & V[]): Compact<T> {
    return arr.filter(Boolean) as Compact<T>;
}
function literalArray<V extends (string | undefined | boolean | object | number | null)>(arr: V[]): V[] {
    return arr.filter(Boolean);
}
let arr = literalArray([0, 1, null, 2, undefined, ''])
let MyDataWithoutFalsy = compact(arr); // 1| 2 ... beacuse resons 
Run Code Online (Sandbox Code Playgroud)