在 TypeScript 中,从多个可能的类型中获得函数中的正确类型。

huangapple go评论78阅读模式
英文:

Get the right type in a function from multiple possible type in typescript

问题

我有点困惑,不知道如何解决我的问题,尽管我已经在类似主题上看到了很多答案。

我有以下类型 - 我稍后会添加更多(大致每个表单一个):

export interface FormError {
  formError: string
}

export interface InputState<T> {
  value: T
  onError: boolean
  validation: FormDataValidation[] | undefined
  errorMessage?: string
}

export interface WorkoutForm extends FormError {
  trainingType: InputState<trainingType>
  name: InputState<string>
  date: InputState<string>
}

export interface LoginForm extends FormError {
  email: InputState<string>
  password: InputState<string>
}

我有以下函数,我想能够使用“通用”类型,以便我可以在WorkoutFormLoginForm或以后创建的其他表单中使用它。

我已经尝试使用T来解决我的问题,但是我的linter每次都会给我很多错误。

public validate<T>(formData: T, index: Exclude<keyof T, 'formError'>): T {
    const validation = formData[index].validation; // << Property 'validation' does not exist on type 'T[Exclude ]'
    // ....... code
    return formData;
}

我想能够像这样使用它,例如:

function handleFormData(index: Exclude<keyof LoginForm, 'formError'>, value: string): void {
  // ... some code
  const currentFormData = formData; // currentFormData type is LoginForm
  currentFormData[index].value = value;
  const validatedData = FormValidation.getInstance().validate<LoginForm>(currentFormData, index);
  // ... some code
}

有没有解决这个问题的提示或想法?

英文:

I'm having a bit of trouble figuring out how to solve my problem, despite the many answers I've already see on similar subjects.

I have the following types -- I'll add more later (one for each form roughly):

export interface FormError {
  formError: string
}

export interface InputState&lt;T&gt; {
  value: T
  onError: boolean
  validation: FormDataValidation[] | undefined
  errorMessage?: string
}

export interface WorkoutForm extends FormError {
  trainingType: InputState&lt;trainingType&gt;
  name: InputState&lt;string&gt;
  date: InputState&lt;string&gt;
}

export interface LoginForm extends FormError {
  email: InputState&lt;string&gt;
  password: InputState&lt;string&gt;
}

I have the following function where I'd like to be able to use a "generic" type so that I can use it with WorkoutForm or with LoginForm or with others that I'll create later.

I've tried to solve my problem with T but my linter gives me lots of errors every time.

public validate&lt;T&gt;(formData: T, index: Exclude&lt;keyof T, &#39;formError&#39;&gt;): T {
    const validation = formData[index].validation; // &lt;&lt; Property &#39;validation&#39; does not exist on type &#39;T[Exclude ]&#39;
    // ....... code
    return formData;
  }

I'd like to be able to use it like this, for example:

function handleFormData(index: Exclude&lt;keyof LoginForm, &#39;formError&#39;&gt;, value: string): void {
  // ... some code
  const currentFormData = formData; // currentFormData type is LoginForm
  currentFormData[index].value = value;
  const validatedData = FormValidation.getInstance().validate&lt;LoginForm&gt;(currentFormData, index);
  // ... some code
}

Any tips or idea to solve this problem?

答案1

得分: 1

You should make validate() generic in both T, the type of formData, as well as K, the type of index. Additionally, you should constrain T and K so that K is a keylike type, and T is known to be an object with a property whose key type is K and whose value type is some InputState<any> (you can use unknown instead of any as long as InputState<T> is covariant in T, see here for more information). That can be written as Record<K, InputState<any>> using the Record<K, V> utility type. Like so:

function validate<T extends Record<K, InputState<any>>, K extends PropertyKey>(
  formData: T, index: K): T {
  const validation = formData[index].validation;
  return formData;
}

That compiles with no error, and now the rest of your code behaves as desired.

Playground link to code

英文:

You should make validate() generic in both T, the type of formData, as well as K, the type of index. Additionally, you should constrain T and K so that K is a keylike type, and T is known to be an object with a property whose key type is K and whose value type is some InputState&lt;any&gt; (you can use unknown instead of any as long as InputState&lt;T&gt; is covariant in T, see https://stackoverflow.com/q/66410115/2887218 for more information). That can be written as Record&lt;K, InputState&lt;any&gt;&gt; using the Record&lt;K, V&gt; utility type. Like so:

function validate&lt;
  T extends Record&lt;K, InputState&lt;any&gt;&gt;,
  K extends PropertyKey&gt;(
    formData: T, index: K): T {
  const validation = formData[index].validation;
  return formData;
}

That compiles with no error, and now the rest of your code behaves as desired.

Playground link to code

<!-- edit -->

huangapple
  • 本文由 发表于 2023年6月29日 21:55:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76581712.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定