TypeScript-Array-Union-Typ in Funktionsparametern
Ich habe einen Unionstyp eines Arrays mit verschiedenen spezifischen Längen:
[ number ] | [ number, number ] | [ number, number, number, number ]
Wie Sie sehen können, gibt es Anforderungen für ein Array mit einem Element, zwei Elementen oder vier Elementen.
Ich versuche, ein Objekt zu erstellen, das eine Funktion mit einer dieser Längen enthält. Wie schreibe ich die Typdefinition, um dies zu ermöglichen?
TS-Spielplatz
Beispiel :
const people: {
name: string,
address: Address,
work: (numbers: [ number ] | [ number, number ] | [ number, number, number, number ]) => any
}[] = [
{
name: "Bob",
address: new Address(),
work: function(numbers: [ number ]): number {
// Implementation returning number
}
},
{
name: "Ashley",
address: new Address(),
work: function(numbers: [ number, number, number, number ]): boolean {
// Implementation returning boolean
}
},
{
name: "Michael",
address: new Address(),
work: function(numbers: [ number, number ]): number {
// Implementation returning number
}
},
]
Derzeit gibt es mir den Fehler:
Der Typ '(numbers: [number]) => number' kann dem Typ '(numbers: [number] | [number, number] | [number, number, number, number]) => any' nicht zugewiesen werden. Die Typen der Parameter 'numbers' und 'numbers' sind nicht kompatibel. Der Typ '[number] | [number, number] | [number, number, number, number]' kann nicht dem Typ '[number]' zugewiesen werden. Der Typ '[number, number]' kann nicht dem Typ '[number]' zugewiesen werden. Die Quelle enthält 2 Elemente, aber das Ziel erlaubt nur 1.ts(2322)
------- Bearbeiten -------
Ich habe einen Vorschlag aus den Kommentaren umgesetzt und alle möglichen Aufrufe in separate Funktionsverbünde anstelle eines Array-Verbunds ausgelagert:
const people: {
name: string,
address: Address,
work: ((numbers: [ number ]) => any) | ((numbers: [ number, number ]) => any) | ((numbers: [ number, number, number, number ]) => any)
}[] = [
Wenn versucht wird, jetzt eine Funktion aus diesem Array aufzurufen:
people[1].work([2, 8, 6, 4])
Es wirft jetzt den folgenden Fehler:
In VSCode habe ich herausgefunden, warum das so ist:
"Die Schnittmenge ''[Nummer] & [Nummer, Nummer] & [Nummer, Nummer, Nummer, Nummer]'' wurde auf ''nie'' reduziert, weil die Eigenschaft ''length'' in einigen Bestandteilen widersprüchliche Typen hat."
Antwort #1
AKTUALISIERT Sie müssen hier Bivarianz verwenden
class Address { }
type Tuple<
N extends number,
Item = number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? Result
: Tuple<N, Item, [...Result, number]>
)
interface WorkFn {
work(numbers: Tuple<1> | Tuple<2> | Tuple<4>): any
}
interface Person extends WorkFn {
name: string,
address: Address,
}
const people: Person[] = [
{
name: "Bob",
address: new Address(),
work(numbers: Tuple<1>) {
const [myNumber] = numbers;
return myNumber * 6
}
},
{
name: "Ashley",
address: new Address(),
work: function (numbers: Tuple<4>): boolean {
const [myNumber, anotherNumber, someNumber, replaceNumber] = numbers;
return myNumber === anotherNumber && someNumber === replaceNumber;
}
},
{
name: "Michael",
address: new Address(),
work: function (numbers: Tuple<2>): number {
const [myNumber, anotherNumber] = numbers;
return myNumber * anotherNumber;
}
},
]
TypeScript-Spielplatz
Hier können Sie den Unterschied zwischen Methodentyp und Pfeilfunktionstyp sowie über Bivarianz finden
Seien Sie also bitte darauf aufmerksam, dass es nicht 100 % sicher ist
Antwort #2
Mein Vorschlag wäre, eine generische Funktion zu verwenden, um das people-Array zu erstellen.
function createPeople<
T extends {
name: string,
address: Address,
work: ((numbers: [ number ]) => any) | ((numbers: [ number, number ]) => any) | ((numbers: [number, number, number, number]) => any)
}[]
>(p: [...T]){
return p
}
const people = createPeople([
{
name: "Bob",
address: new Address(),
work: function(numbers: [ number ]): number {
const [ myNumber ]: [ number ] = numbers;
return myNumber * 6
}
},
{
name: "Ashley",
address: new Address(),
work: function(numbers: [ number, number, number, number ]): boolean {
const [ myNumber, anotherNumber, someNumber, replaceNumber ]: [ number, number, number, number ]= numbers;
return myNumber === anotherNumber && someNumber === replaceNumber;
}
},
{
name: "Michael",
address: new Address(),
work: function(numbers: [ number, number ]): number {
const [ myNumber, anotherNumber ]: [ number, number ] = numbers;
return myNumber * anotherNumber;
}
},
])
TypeScript weiß jetzt, was der Callback jedes Indexes ist. Das macht die folgenden Aufrufe strikt typisiert.
people[1].work([2, 8, 6, 4])
people[2].work([1, 2])
Spielplatz

