如何根据输入指定typescript函数返回接口?

jw5wzhpr  于 2022-11-18  发布在  TypeScript
关注(0)|答案(1)|浏览(133)
interface Itest {
  a: { a: number };
  b: { b: number };
  c: { c: number };
  d: { d: number };
}

type Tname = keyof Itest;

interface Isdk {
    init: (
        dep: Tname[],
        param: (<T extends Tname, K = Itest[T]>(name: T) => K | undefined) | Itest[Tname]
    ) => void;
}

const SDK: Isdk = {
    init: (dep, param) => {},
};

SDK.init(['a'], (name) => {
    if (name === 'a') {
        return {
            a: 1,
        };
    }
    if (name === 'b') {
        return {
            a: 1,
        };
    }
    if (name === 'c') {
        return {
            a: 1,
        };
    }
    if (name === 'd') {
        return {
            a: 1,
        };
    }
    return;
});

我想根据输入定义返回接口,例如,如果名称是a,那么返回值必须是{ a: number }

lf5gs5x2

lf5gs5x21#

您的代码的问题是,当您通过if (name === "a") {return {a: 1}}检查generic类型K的值name时,此narrows的类型为name,* 但当前它不会缩小或重新约束类型K本身 *。
你应该返回indexed access类型的值Test[K],但是当你返回return {a: 1}时,编译器无法验证这是否合适。如果K可以被限制为"a",那么Test[K]可以被计算为Test["a"],即{a: number}。然后{a: 1}将被接受。但这并没有发生,所以你会得到一个编译器错误。
对于所有其他检查if (name === "b")等,也是如此。
这是TypeScript的一个局限性,GitHub中有很多开放的功能要求在这里进行一些改进。如果microsoft/TypeScript#33014和/或microsoft/TypeScript#27808被实现,它可能会让你的代码按原样编译。
但在TypeScript 4.9中,它不是语言的一部分。
现在,如果您希望以编译器可以验证为安全的方式返回Test[K]这样的泛型索引访问类型的值,最好的方法是 * 实际执行一个索引操作 *,如return test[name],其中test的类型为Testname的类型为K
你的函数中已经有name了,让我们重构一下,这样我们也可以提供test

SDK.init(['a'], (name) => {
  const test: Test = {
    get a() { return { a: 1 } },
    get b() { return { b: 1 } },
    get c() { return { c: 1 } },
    get d() { return { d: 1 } }
  }
  return test[name];
}); // okay

变量testTest类型的对象。每个属性都实现为a getter method,因此在运行时只计算您实际关心的属性。
这会成功编译,因为test[name]已知为Test[K]类型。
Playground代码链接

相关问题