首页 > 解决方案 > Typescript:数组元素的类型推断

问题描述

我想在不使用任何 T 的情况下获得以下行为:

interface Test<T> {
  sameField: string;
  test: T
  testFunction: (e: T) => void
}

const array: Array<Test</*something something*/_>> = [
  {
    sameField: "foo",
    test: 1,
    testFunction: (e) => {
      e.toExponential(2) // Should be Valid
      e.indexOf('e') // Should be Invalid
    }
  },
  {
    sameField: "bar",
    test: "baz",
    testFunction: (e) => {
      e.indexOf('e') // Is Valid
      e.toExponential(2) // Should be Invalid
    }
  }
]

它背后的想法只是告诉 Typescript“让数组元素自己处理它们的输入”的一种方式。只能在 Typescript 中进行吗?

标签: typescripttypescript-generics

解决方案


TS 自己无法e在这种数据结构中推断参数。

您在这里有几个选择。

第一的

test预先定义您的财产:

type Main = {
    foo: string;
    bar: number;
};

type Validator<T extends keyof Main> = {
    test: T;
    isValid: (value: Main[T]) => boolean;
};

type Values<T> = T[keyof T]

type MainValidationRule = Values<{
    [P in keyof Main]: {
        test: P;
        isValid: (value: Main[P]) => boolean;
    }
}>

const validators: Array<MainValidationRule> = [
    { test: 'foo', isValid: (value/* infered to stirng */) => true },
    { test: 'bar', isValid: (value/* infered to number */) => true }
]

第二

interface Test<T> {
    field: string;
    test: T
    fn: (e: T) => void
}

const builder = <Test, Field>(test: Test, field: Field, fn: (e: Test) => any) => ({
    field,
    test,
    fn
})

const array = [builder(2, 'hello', (e/**infered to number */) => 42)]

在这里,在我的博客中,您可以找到有关使用和键入回调的更多信息

还有另一种方法:

interface Foo {
    sameField: "foo",
    test: 1,
    testFunction(e: this['test']): void
}

const x: Foo = {
    sameField: "foo",
    test: 1,
    testFunction(e) {
        e.toExponential(2) // ok
        e.indexOf('e') // error
    }
}

但正如您可能已经注意到的那样,您应该预先声明您的sameFieldtest

有更多的选择,但我相信这将是一个开销


推荐阅读