tipuri - comportament ciudat al interfeței parțiale în Typescript


Am dat peste niște cod care părea complet greșit într-un repo la care lucrez. Mai jos este un exemplu de ceea ce am găsit.

interface Car {
  make: string
  model: string
}

type SomeType = Partial<Car>

const car: SomeType = {}

if (car === "typescript doesn't complain about this") {
    // This code will never execute..?
}

Îmi scapă ceva? car nu va fi niciodată egal cu un șir de caractere, nu? De obicei, când încerci să compari două tipuri diferite care nu au nicio suprapunere, Typescript va striga la tine și îți va spune că se va întoarce mereu fals. Orice ajutor în această privință ar fi foarte apreciat!

Răspuns #1

Partial<Car> este un tip slab deoarece toate proprietățile sale sunt opționale. TypeScript 2.4 a adăugat o verificare care te-ar avertiza dacă ai încerca să atribui ceva de genul unui string unui tip slab, deoarece nu există proprietăți comune:

let car: { make?: string, model?: string };
car = {}; // okay
car = "oops"; // error! Type '"oops"' has no properties in common with type 
// '{ make?: string | undefined; model?: string | undefined; }'.

Dar înainte de TypeScript 2.4, car="oops" ar fi fost permis fără nicio eroare, deoarece niciunul dintre membrii aparenti ai "oops" (cum ar fi length și toUpperCase) nu intră în conflict cu Partial<Car>. Din punct de vedere structural, un string este un Partial<Car>. Totuși, atribuirea este probabil o greșeală și detectarea tipului slab te avertizează în legătură cu aceasta.


Această detectare slabă a tipului pare să se aplice doar asignabilității, totuși. Nu intervine pentru operatorii de comparație, așa cum ai observat:

if (car === "oops") {  } // no error

Există o cerere de funcționalitate deschisă la microsoft/TypeScript#32627 care solicită ca acest lucru să fie schimbat. Dacă îți pasă suficient de mult încât să vezi acest lucru schimbat, ai putea să mergi la acea problemă, să dai un 👍 și, poate, să oferi un argument convingător pentru motivul pentru care acest lucru contează pentru tine. Dar mă îndoiesc că ar avea prea mult efect, și nu există nicio indicație că va fi implementat, deoarece nu există implicare din partea comunității. Probabil oamenii nu se confruntă foarte des cu această situație în codul real.


Deci, răspunsul la întrebarea ta așa cum a fost pus este: detectarea tipului slab nu a fost niciodată implementată pentru operatorii de comparație și nu pare să existe o mare cerere pentru ca acest lucru să se schimbe.

Link de teren de joacă către cod

Răspunsul #2

Partial<T> va permite întotdeauna tipul {} (când nu sunt furnizate chei).

{} are unele... ciudățenii.

Este aproape ca și cum ai folosi any. Aproape fiecare valoare în JavaScript poate fi atribuită tipului {}. Pentru că gândește-te. Nu necesită ca valoarea să aibă vreo cheie. Orice are cel puțin niște chei, așa că prin tipizarea structurală, orice corespunde acestui tip.

Observați că dacă omiteți SomeType, rezultatul va fi același:

const car = {}; // now inferred as '{}'

if (car === "typescript doesn't complain about this") {

}

TypeScript nu se plânge din acest motiv deoarece, în ochii săi, este posibil ca condiția să fie executată (tipurile se suprapun, șirurile sunt atribuibile la {}).