【问题标题】:How to dynamically set the type of constructor function method in TypeScriptTypeScript中如何动态设置构造函数方法的类型
【发布时间】:2022-01-13 14:26:04
【问题描述】:

我正在尝试创建一个类或构造函数,我指定了一个值列表,用于其中一个方法的类型。

作为一个例子,我有这个代码。

const MyAnimal = function (animal: string[]) {
  type Animal = typeof animal[number]

  this.getAnimal = (url: Animal) => {
    console.log(url)
  }
}

const animalTest = new MyAnimal(['sheep', 'dog', 'cat'])
// I would like this to fail as 'mouse' is not part of the array ['sheep', 'dog', 'cat']
animalTest.getAnimal('mouse')

我希望 getAnimal 具有 'sheep' | 'dog' | 'cat' 类型,并且如果我添加不同的内容,智能感知会警告我

这可能吗?

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    您可以通过一个泛型类型参数和一个 readonly 动物数组来做到这一点,就像这样;

    class MyAnimal<Animal> {
        constructor(public animals: readonly Animal[]) {
        }
        getAnimal(url: Animal) {
            console.log(url);
        }
    }
    
    const animalTest = new MyAnimal(['sheep', 'dog', 'cat'] as const);
    animalTest.getAnimal('mouse'); // Error as desired
    animalTest.getAnimal('sheep'); // Works
    

    Playground link

    TypeScript 可以推断字符串文字联合类型作为 Animal 类型参数的类型参数,因为数组是 readonly(我们通过 as const 调用构造函数时满足这一点),所以 TypeScript 知道它赢了'在运行时不改变。

    【讨论】:

    • 非常感谢您的回复.. 作为下一步 - 有没有一种方法可以代替传入字符串数组,而是传入对象数组,其中对象包含要推断为类型的字符串,例如{ name: 'tiger', url: 'https:....' }, { name: 'sheep', url: 'https://...' }
    • @user3284707 - 当然,TypeScript 也可以推断出,您只需根据 Animal 类型参数指定对象的形状:tsplay.dev/mqQZ2m
    • 这几乎正是我所需要的,除了我需要尝试现在传入一个项目数组,而不是像您的示例中那样对它们进行硬编码。这可能吗,当我尝试时它会以未知的形式返回
    • 我在这里尝试过,但没有任何想法? typescriptlang.org/play?#code/…
    • @user3284707 - 您不能对动态数据执行此操作,因为类型是 TypeScript 中的编译时概念。请参阅答案末尾的注释。
    【解决方案2】:

    为了推断字面量类型,可以使用variadic tuple types

    type Animal<Name extends string> = {
        name: Name,
        url: `https://${string}`
    }
    
    class MyAnimal<
        Name extends string,
        Item extends Animal<Name>,
        List extends Item[]
        > {
        constructor(public animals: [...List]) {
        }
    
        // You should get "url" from infered list and not from Item["url"]
        getAnimal<Url extends List[number]['url']>(url: Url) {
            console.log(url);
        }
    }
    
    const animalTest = new MyAnimal(
        [
            { name: 'sheep', url: 'https://sheep.com', },
            { name: 'dog', url: 'https://dog.com', },
            { name: 'cat', url: 'https://cat.com', }
        ]);
    
    animalTest.getAnimal('https://dog.com'); // ok
    animalTest.getAnimal('https://mouse.com'); // expected error
    

    Playground

    如果您想了解更多关于字面量类型推断的信息,可以查看我的article。目标是为泛型参数提供尽可能多的约束。如果有足够的约束,TS 将推断字面量类型。

    【讨论】:

    • 太棒了,非常感谢
    猜你喜欢
    • 2020-06-25
    • 2021-01-19
    • 1970-01-01
    • 2020-11-20
    • 2022-06-25
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    相关资源
    最近更新 更多