英文:
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>
}
我有以下函数,我想能够使用“通用”类型,以便我可以在WorkoutForm或LoginForm或以后创建的其他表单中使用它。
我已经尝试使用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<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>
}
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<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;
  }
I'd like to be able to use it like this, for example:
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
}
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.
英文:
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 https://stackoverflow.com/q/66410115/2887218 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.
<!-- edit -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论