Typescript 条件类型和对象属性

3

在 TypeScript 中,是否可以声明一个通用类(或工厂函数,如示例中所示),接受一个二进制条件类型变量,影响类属性类型和相关函数?

例如:

export function CreateModel<T extends 'CREATE' | 'UPDATE'>(mode: T) {
  type valueType = T extends 'CREATE' ? { name: string } : { name: string; email: string };
  return {
    value: {} as valueType,
    onChange(change: Partial<valueType>) {
      if (mode === 'UPDATE') {
        this.value.email = change.email;
      }
    }
  };
} 

你有一个可用的代码示例,但你想知道是否可能实现。既然你的代码可以编译,我认为这是可能的。你到底在问什么?哪些部分出了问题? - FiniteLooper
它在我的电脑上无法编译(TS 3.5.1) - Daniel
具体是什么出了问题? - FiniteLooper
即使模式为UPDATE,它也无法推断出电子邮件存在于值的类型上。 - Daniel
这可能与 https://github.com/microsoft/TypeScript/issues/28889 有关。 - SLaks
1个回答

0

看起来你正在使用 T extends 'CREATE' | 'UPDATE' 扩展一个字符串,我不确定你是否可以这样做。这基本上是在说“它可以是任何字符串或这两个特定的字符串” - 这本质上与说“任何字符串”相同。

如果你想表达的是你只希望输入值为 'CREATE''UPDATE',那么你只能通过以下方式允许这两个字符串:CreateModel(mode: 'CREATE' | 'UPDATE')

另一个问题是你正在使用 this,但你处于一个函数内部,而不是一个类中,所以它的工作方式并不完全相同,你可能会遇到一些问题。通常情况下,这是不被鼓励的,你应该使用一个类。

这是我想到的,它可以编译。我知道它有点偏离了你最初的问题,但我认为这也是因为你没有在这里使用类。

type ICreateType = { name: string };
type IUpdateType = { name: string; email: string | undefined };
interface IReturnCreateValue {
  value: ICreateType,
};
interface IReturnUpdateValue {
  value: IUpdateType,
  onChange: (change: Partial<IUpdateType>) => void;
};

export function CreateModel(mode: 'CREATE' | 'UPDATE'): IReturnCreateValue | IReturnUpdateValue { 
  if (mode === 'CREATE') {
    return { value: { name: '' } };
  }

  let value: IUpdateType = { name: '', email: '' };
  return {
    value: value,
    onChange(change: Partial<IUpdateType>) {
      value.email = change.email;
    }
  };
};

CreateModel('CREATE');
CreateModel('UPDATE');
CreateModel('foo'); //compile error

这是一个关于如何将其作为类实现的想法(也可以参考typescript playground

type IValueType = { name: string; email?: string };
interface IValue {
  value: IValueType,
  onChange?: (change: Partial<IValueType>) => void;
};

class CreateModel {
  value: IValueType = { name: '' };
  onChange: undefined | ((c: Partial<IValueType>) => void) = undefined;

  constructor(private readonly shouldUpdate: boolean) {
    if (this.shouldUpdate) {
      this.onChange = (change: Partial<IValueType>) {
        this.value.email = change.email;
      }
    }
  }
}

const a = new CreateModel(false);
const b = new CreateModel(true);

感谢你的详细评论,Chris。我怀疑类示例不相关,因为电子邮件是一种相互属性,而在我的情况下,属性不是相互的。我仍在考虑你写的第一个示例。再次感谢! - Daniel
在第一个示例中,您声明了不依赖于“模式”的不同接口。我不想声明不同的接口,并且我想将返回类型“绑定”到“模式”。基本上,我只是想要一个根据某些“模式”行为略有不同的类。再次感谢。 - Daniel
是的,我知道 - 我不知道你的使用情况,所以我只是试图猜测它可能如何被使用以及我如何利用我所知道的来完成它。我看到你想做什么了,但是可能确实不可能。 - FiniteLooper
1
你对 T extends 'CREATE' | 'UPDATE' 的理解是错误的。这是有效的语法。它意味着 T 可以是 'CREATE''UPDATE' 或联合类型 'CREATE' | 'UPDATE' - Linda Paiste

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接