Typescript Array[T] aksepterer {..T} som gyldig type


Dette bet meg da jeg brukte useState<Options[]> som en React-hook, når jeg skrev {...options} i stedet for [...options], jeg fant det først ut da jeg prøvde å få tilgang til .map av "array" (objekt) og fikk en TypeError. La meg gi deg et eksempel som kan klargjøre spørsmålet mitt:

  interface Option {
    title: string;
    isSelected?: boolean;
  }

  function myFunc(options: Option[]): void {}

  const options: Option[] = [{title: 'Male', isSelected: true}, {title: 'Female'}, {title: 'Other'}];
  const options2 = {...options};
  myFunc(options);
  myFunc(options2); // why isn't this an error ?

Svar #1

Dette ser faktisk ut til å være et problem med Typescript selv:

let c: number[] = { ...[0, 1, 2] }; // compiles
c.fill(0) // runtime error

let d: number[] = Object.assign({}, [0, 1, 2]);  // compiles
d.fill(0) // runtime error

Videre kompilerer dette også og krasjer under kjøring:

class E {
    method() { }
}

let e: E = Object.assign({}, new E)
e.method() // runtime error

PG

Jeg antar at dette er fordi Object.assign er deklarert som

assign<T, U>(target: T, source: U): T & U;

som er feil, siden det assign returnerer faktisk ikke utvider U. Returtypen til assign bør være noe som T & OwnProperties<U>, men dette er for øyeblikket ikke mulig, se

  • https://github.com/microsoft/TypeScript/issues/28801
  • https://github.com/microsoft/TypeScript/issues/9726

Svar #2

Leker rundt på TypeScript-lekeplassen, det ser ut til at TypeScript mener options2 er definert som:

const options2: {
    [x: number]: Option;
    length: number;
    toString(): string;
    toLocaleString(): string;
    pop(): Option | undefined;
    push(...items: Option[]): number;
    concat(...items: ConcatArray<Option>[]): Option[];
    concat(...items: (Option | ConcatArray<...>)[]): Option[];
    ... 24 more ...;
    [Symbol.unscopables](): {
        ...;
    };
}

Så det ser faktisk ut som et array av typen Option Option[]. Men spread-operatoren kopierer faktisk ikke Array-prototypemedlemmer, og det nye objektet er definitivt ikke et array. Jeg vil si at dette er en feil i TypeScript-typesystemet.

Relaterte artikler