typescript - Hvorfor kan ikke et grensesnitt tilordnes til Record?


Jeg merket nettopp at et grensesnitt ikke kan tilordnes til Record<string, unknown> (playground-lenke):

interface Foo {
    foo: number
}

const foo: Foo = { foo: 1 }
const bar: Record<string, unknown> = foo
//    |-> Error: Type 'Foo' is not assignable to type 'Record<string, unknown>'
//               Index signature is missing in type 'Foo'.(2322)

Men det samme er mulig, når typedeklarasjonen for Foo utelates (playground-lenke):

const foo = { foo: 1 }
const bar: Record<string, unknown> = foo // no error here

Spørsmål: Hvorfor er det en forskjell mellom begge eksemplene? For meg er den reduserte typen til variabelen foo den samme i begge eksemplene... Burde ikke grensesnittet Foo kunne tilordnes til Record<string, unknown>?

Etter min forståelse er Record<string, unknown> ekvivalent med object, og derfor bør enhver grensesnitt kunne tilordnes til det. Også @typescript-eslint/ban-types foreslår å bruke Record<string, unknown> i stedet for object.

Merknader: Det første eksempelet fungerer når enten object (playground-lenke) eller Record<string, any> (playground-lenke) brukes i stedet for Record<string, unknown>.

Svar #1

Du har støtt på Indekssignatur mangler i type (kun på grensesnitt, ikke på typealias) #15300

Koden vil fungere når du endrer et grensesnitt til en type:

type Foo = {
    foo: number
}

const foo: Foo = { foo: 1 };
const bar: Record<string, unknown> = foo;

Svar #2

REDIGER: @Lesiak har det riktige svaret ovenfor. Jeg lar dette stå kun for lenken til det relaterte svaret.

Admittedly, jeg er litt ute av mitt dybde her, men jeg ser gjennom dette svaret og jeg ser:

En stor del av TypeScripts sikkerhet kommer fra det faktum at [...] det bare lar deg behandle et objekt som en ordbok hvis det vet at det uttrykkelig er ment som en.

Noe som er i samsvar med mine tester. Å endre grensesnittet ditt for å eksplisitt behandle Foo.foo som en indeks gir ikke feilen. (playground-lenke)

interface Foo {
    [foo: string]: number
}

const foo = { foo: 1 }
const bar: Record<string, unknown> = foo

Dette svarer ikke fullt ut på spørsmålet ditt, siden Record<string, any> fungerer med ditt eksplisitte grensesnitt, men kanskje noen mer kunnskapsrike kan ta det herfra.

Relaterte artikler