首页 > 解决方案 > Type inference from array of elements

问题描述

I have a code similar to this:

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

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

I cant understand why TypeScript's type inference is getting (string | number)[] instead of [string, number].

Do I have to specifically tell TypeScript arr2: [string, number] or maybe there is easier way?

Above example is simple, but problem is more annoying with this:

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

Type inference: (string | boolean | React.RefObject<HTMLInputElement> | React.Dispatch<React.SetStateAction<string>> | React.Dispatch<React.SetStateAction<boolean>>)[]

So to make it what I need I have to define return type manually:

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

标签: typescript

解决方案


Typescript 通常不会为数组文字推断元组。有几种方法可以在没有显式类型的情况下推断元组(具有显式类型的版本也可以正常工作,但您可能希望避免重复)。

选项 1:使用通用函数

如果我们有一个其余参数类型的类型参数,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 断言。这有几个副作用,其中之一是推断元组。另一种是推断只读元组并推断所有文字的文字类型,这可能会使此解决方案不像函数那样通用,但您可以根据需要混合和匹配:

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

推荐阅读