根据元素数组进行类型推断

时间:2019-04-05 08:36:51

标签: typescript

我有一个与此相似的代码:

const x = 'a';
const y = 1;

const arr1 = [x, y];                   // -> (string | number)[]
const arr2: [string, number] = [x, y]; // -> [string, number]

我不明白为什么TypeScript的类型推断会得到(string | number)[]而不是[string, number]

我必须专门告诉TypeScript arr2: [string, number]还是有更简单的方法?

上面的例子很简单,但是问题更令人讨厌:

function useFormField() {
  const [field, setField] = useState('');
  const [fieldError, setFieldError] = useState(false);
  const fieldRef = useRef<HTMLInputElement>(null);
  return [field, setField, fieldError, setFieldError, fieldRef];
}

类型推断:(string | boolean | React.RefObject<HTMLInputElement> | React.Dispatch<React.SetStateAction<string>> | React.Dispatch<React.SetStateAction<boolean>>)[]

要使其成为我需要的,我必须手动定义返回类型:

function useFormField(): [string, React.Dispatch<React.SetStateAction<string>>, boolean, React.Dispatch<React.SetStateAction<boolean>>, React.RefObject<HTMLInputElement>]{
  // ...
}

1 个答案:

答案 0 :(得分:1)

Typescript通常不会推断数组文字的元组。没有显式类型的元组可以通过多种方法进行推断(具有显式类型的版本也可以工作,但您可能希望避免重复)。

选项1:使用通用函数

如果我们具有rest参数类型的类型参数,Typescript会推断出元组

function tuple<T extends any[]>(...a: T) {
    return a
}
let r = tuple(1,2,3) // [number, number, number]

另一种选择,如果我们要保留数组文字语法,则使用既是数组又是单个元素元组(any | any[])的约束,单个元素元组将向编译器提示我们想要的一个元组,但是数组将允许该元组具有任意大小:

function tuple<T extends [any] | any[]>(a: T) {
    return a
}
let r = tuple([1,2,3]) // [number, number, number]

选项2:使用as const(用于TS 3.4及更高版本)

3.4添加所谓的const assertion。这有几个副作用,其中之一就是推断元组。另一个是推断一个只读的元组并推断所有文字的文字类型,这可能会使此解决方案不像该函数那样普遍,但是您可以根据需要进行混合和匹配:

let r = [1,2,3] as const // [1,2,3]