Typescript:确保所有属性使用相同的元组类型

Hen*_*Jan 6 tuples type-safety typescript typescript-generics

我有一个具有泛型的函数,它是 1 个元素的元组或 2 个元素的元组。
我想确保函数中使用的所有属性都使用相同长度的元组。

type TypeA = [string] // Tuple of 1 element
type TypeB = [string, string] // Tuple of 2 elements
type Header = TypeA | TypeB

interface SomeObject<H extends Header> {
    prop1: H
    prop2: H
}

function useHeader<H extends Header>(someObject:SomeObject<H>) {
    // do something
}

useHeader({
    prop1: ["tuple of 1 element"],
    prop2: [
        "tuple of", 
        "2 elements"
    ] // <-- I want an error here, because prop1 and prop2 use diffrent tuples
})
Run Code Online (Sandbox Code Playgroud)

我注意到,当我更改TypeA为number和TypeBtostring时,当我混合数字和字符串时,Typescript 会出错。
当使用不同长度的元组时,是否可以使 Typescript 生成错误?

cap*_*ian 7

考虑这种方法:

type TypeA = [string] // Tuple of 1 element
type TypeB = [string, string] // Tuple of 2 elements

type Header = TypeA | TypeB

interface SomeObject<H extends Header> {
    prop1: H
    prop2: H & {} // <------- CHANGE IS HERE
}

function useHeader<H extends Header>(someObject: SomeObject<H>) {
    // do something
}

useHeader({
    prop1: ["tuple of 1 element"],
    prop2: [
        "tuple of",
        "2 elements"
    ] // <-- I want an error here, because prop1 and prop2 use diffrent tuples
})
Run Code Online (Sandbox Code Playgroud)

操场

该行的H & {}意思是“降低推理优先级”。换句话说,TS 将首先推断Hfor prop1,然后才推断第二个prop2,而不是同时推断。

虽然这不是记录在案的功能,但 Ryan Cavanaugh(TypeScript 团队的开发负责人)在此表示,它是“......设计......”(带有强调)并且“......可能会在可预见的未来发挥作用。 ”

您可以在我的博客中找到更多未记录的功能。这个答案中提供了这个特殊的技巧


没有未记录的技巧:

type TypeA = [string] // Tuple of 1 element
type TypeB = [string, string] // Tuple of 2 elements

type Header = TypeA | TypeB
type IsLengthEqual<T extends any[], U extends any[]> = U extends { length: T['length'] } ? U : never

interface SomeObject<H extends Header, H2 extends Header> {
    prop1: H
    prop2: IsLengthEqual<H, H2>
}

function useHeader<H extends Header, H2 extends Header>(someObject: SomeObject<H, H2>) {
    // do something
}

useHeader({
    prop1: ["tuple of 1 element"],
    prop2: [
        "tuple of",
        'dfg'
    ] // error
})
Run Code Online (Sandbox Code Playgroud)

并且只有一个通用的

type TypeA = [string] // Tuple of 1 element
type TypeB = [string, string] // Tuple of 2 elements

type Header = TypeA | TypeB

interface SomeObject<H extends Header> {
    prop1: H
    prop2: { [Prop in keyof H]: string }
}

function useHeader<H extends Header>(someObject: SomeObject<[...H]>) {
    // do something
}

useHeader({
    prop1: ["tuple of 1 element"],
    prop2: [
        "tuple of",
        'dfg'
    ] // error
})
Run Code Online (Sandbox Code Playgroud)