类型“keyof T”不满足约束

use*_*949 7 typescript typescript-generics

尽管验证有效,但我还是收到此错误。我所需要的只是一个函数,该函数使用对象来生成另一个函数来过滤固定类型的参数

Type 'keyof T' does not satisfy the constraint '"a" | "b" | "c"'.
  Type 'string' is not assignable to type '"a" | "b" | "c"'.
    Type 'keyof T' is not assignable to type '"c"'.
      Type 'string' is not assignable to type '"c"'
Run Code Online (Sandbox Code Playgroud)

type GM = {
    a: number;
    b: string;
    c: string
}

type VMeth<T, C > = (old: T, n: C) => any;

const getVF = <T extends { [key in keyof Partial<GM>]: 1 }>(part: T):  VMeth<GM, Pick<GM, keyof T>> => {
    return function(){ } as any
}

const fd = getVF({ a: 1 });

fd({ a: 1, b: "", c: "s"}, { a: 1 });
Run Code Online (Sandbox Code Playgroud)

游乐场链接

jca*_*alz 4

约束条件

T extends { [key in keyof Partial<GM>]: 1 }
Run Code Online (Sandbox Code Playgroud)

意味着T必须可分配给{a?:1, b?:1, c?:1}. 这包括您尝试支持的类型,例如{a: 1}. 但它也包括您显然不想支持的类型。TypeScript 中的对象类型是可扩展的开放的(而不是精确的封闭的)。您可以通过向对象添加属性来扩展对象类型。{a?: 1, b?:1, c?:1, oops: string}所以也支持该类型:

const oopsie = getVF({ a: 1, oops: "oops" }) // no error!
// const oopsie: VMeth<GM, Pick<GM, "a" | "oops">>
Run Code Online (Sandbox Code Playgroud)

因为T实际上可能比 拥有更多的键GM,所以编译器正确地抱怨

// Type 'keyof T' does not satisfy the constraint 'keyof GM'.
Run Code Online (Sandbox Code Playgroud)

如果您确实想将 的键限制part为 的键GM(或者至少只注意这些键​​,因为无论您做什么,对象类型都是开放的),您可以使您的函数在这些键中通用K

const getVF = <K extends keyof GM>(part: Record<K, 1>):
    VMeth<GM, Pick<GM, K>> => {
    return function () { } as any
}
Run Code Online (Sandbox Code Playgroud)

现在K必须是 的并集的某个子集"a" | "b" | "c",不能是"oops"或其他任何东西。所以Pick<GM, K>永远有效。您想要的用例仍然具有相同的功能:

fd({ a: 1, b: "", c: "s" }, { a: 1 });
// const fd: (old: GM, n: Pick<GM, "a">) => any
Run Code Online (Sandbox Code Playgroud)

现在,如果我们明显添加意外的属性,我们会收到编译器警告:

getVF({ a: 1, oops: "oops" }); // error, excess property!
Run Code Online (Sandbox Code Playgroud)

如果你偷偷摸摸,你仍然可以设法在那里获得如此多的财产:

const existingObj = {a: 1, oops: "oops"} as const;
const aliased: {a: 1} = existingObj;
const okay = getVF(aliased); // no error
// const okay: VMeth<GM, Pick<GM, "a">>
Run Code Online (Sandbox Code Playgroud)

但至少出来的值仍然是Pick<GM, "a">,而不是像 那样的无效值Pick<GM, "a" | "oops">


Playground 代码链接