Consider this approach:
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
})
Playground
This line H & {}
means "make inference priority lower". In other words, TS will infer first H
for prop1
and only then second prop2
and not simultaneously.
While this is not documented feature, Ryan Cavanaugh (development lead of the TypeScript team) says here that it's "...by design..." (w/emphasis) and "...probably going to work for the foreseeable future."
More undocumented features you can find in my blog. This particular hack was provided in this answer
WIhout undocumented tricks:
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
})
And with only one generic
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
})