如何在 TypeScript 中根据动态值返回对应类型?

新手上路,请多包涵

在 typescript 中如果根据动态值返回对应的类型.例如

type Params = {
    type: 'human' | 'animal',
    id: 'xxxxxx'
}

function test( val: Params) {
    switch(val){
        case 'human': return new A(val.id);
        case 'animal': return new B(val.id);
    }
}

// 这里的 result 并不会推导出 A,要怎么样才能让result推导得A呢?
const result = test({ type: 'human', id: 1});

我像这么做并不可行

class A {
  name: string;

  constructor(val) {
    this.name = val;
  }
}

class B {
  age: number;

  constructor(val) {
    this.age = val
  }
}

function getValue(key: string) {
  switch (val) {
    case 'wxapp': return new A('hello');
    case 'local': return new B(18);
  }
}

const s = getValue('wxapp');
阅读 386
avatarAI BotBETA

在 TypeScript 中,你可以使用泛型来实现基于动态值返回对应类型的功能。对于你给出的示例,你可以对 test 函数使用泛型,并在函数内部根据 Params 对象的 type 属性返回对应的类型。

下面是一个可能的实现方式:

type Params = {
 type: 'human' | 'animal',
 id: string | number
}

class A {
 name: string;

 constructor(val: string) {
 this.name = val;
 }
}

class B {
 age: number;

 constructor(val: number) {
 this.age = val;
 }
}

function test<T extends Params>(val: T): T['type'] extends 'human' ? A : T['type'] extends 'animal' ? B : never {
 switch (val.type) {
 case 'human':
 return new A(val.id as any); // 这里使用 any 断言是因为 val.id 的类型可能是 string | number,而 A 的构造函数参数需要是 string
 case 'animal':
 return new B(val.id as any); // 同上
 default:
 throw new Error(`Unexpected type: ${val.type}`);
 }
}

const result = test({ type: 'human', id: 'JohnDoe' }); // result 的类型会被推导为 A
result.name; // 可以访问 A 类的 name 属性

const animalResult = test({ type: 'animal', id: 42 }); // animalResult 的类型会被推导为 B
animalResult.age; // 可以访问 B 类的 age 属性

在上面的代码中,我们使用了条件类型(Conditional Types)来根据 Params 对象的 type 属性返回对应的类型。当 type'human' 时,函数返回 A 类型;当 type'animal' 时,函数返回 B 类型。如果 type 是其他值,函数会抛出一个错误。

注意,在调用 new A(val.id as any)new B(val.id as any) 时,我们使用了 as any 断言。这是因为 val.id 的类型可能是 string | number,而 A 的构造函数参数需要是 stringB 的构造函数参数需要是 number。使用 as any 断言可以绕过类型检查,但需要注意确保传递的参数是正确的类型,以避免运行时错误。

此外,你还可以考虑使用工厂函数或工厂类来创建对象,这样可以根据传入的参数动态地创建和返回正确的类型。这样可以避免在 test 函数中使用 as any 断言,并使代码更加清晰和易于维护。

1 个回答

一个粗糙的方案:

class A {
  name: string;

  constructor(val) {
    this.name = val;
  }
}

class B {
  age: number;

  constructor(val) {
    this.age = val;
  }
}

function getValue(key: 'wxapp'): A;
function getValue(key: 'local'): B;

function getValue(key: 'wxapp' | 'local') {
  switch (key) {
    case 'wxapp':
      return new A('hello');
    case 'local':
      return new B(18);
  }
}

const a = getValue('wxapp');
const b = getValue('local');
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏