microsoft / microsoft/TypeScript
Inherited typing for class property initializers
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.3k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
Problem
Initializing a class member with things like { }, null, undefined, or [] has unexpected behavior.
class Base {
favorites = ["red", "blue"];
}
class Derived extends Base {
favorites = [];
constructor() {
this.favorites.push('green'); // Can't push string onto never[], wat?
}
}
interface Settings {
size?: number;
color?: string;
}
class Base {
settings: Settings = { size: 42 };
}
class Derived extends Base {
settings = { };
constructor() {
if (big) this.settings = { siz: 100 }; // no error, wat?
}
}
Solution
New rule: When a class property is initialized with exactly null, undefined, { }, or [], the type of the property is taken from the same property of the inherited type (if one exists), rather than the type of the initializer.
The inherited type is B & I1 & I2 & ... where B is the base class and I1, I2, ... are the implemented interfaces of the class.
Examples
interface Positionable {
position: string | null;
}
class MyPos implements Positionable {
position = null;
setPos(x: string) {
this.position = x;
}
getPos() {
return this.position.subtr(3); // error detected
}
}
class Base {
items = ['one'];
}
class Derived extends Base {
items = []; // no longer an implicit any
}
var x = new Derived();
x.items.push(10); // Error as expected
Bad Ideas We Thought Were good

Contextual typing plays poorly with other behavior such as unit type positions. Consider
enum E { A, B, C }
class Base {
thing = E.A;
}
class Derived extends Base {
thing = E.B;
change() {
this.thing = E.C; // Error! wat
}
}
This turns into a big problem because the E.B expression is contextually typed by the unit-like type E.A | E.B | E.C and so acquires the specific type E.B rather than the intended type E! Daniel found this break in Azure.
/cc conspirators @DanielRosenwasser @sandersn
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
La issue non indica file, test o punti di ingresso. Inizia individuando la logica di inferenza dei tipi e di type-checking delle proprietà di classe di TypeScript, quindi usa gli esempi Base/Derived e implements come casi di regressione. Il lavoro è completato quando null, undefined, {} e [] ereditano il tipo di proprietà corrispondente senza introdurre il problema di contextual typing di enum descritto qui.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Tranquilla
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 38/100