generics - Varför kontrolleras inte first class-funktioner typmässigt i TypeScript?
I exemplet nedan har Promise::then-besöksfunktionen f en förväntning om att ta emot ett Example. Om jag uttryckligen skickar in ett felaktigt objekt med saknade egenskaper får jag ett typerrors.
Men om jag helt enkelt skickar funktionen f till .then(f) får jag inget typfel, även om TypeScript vet att typen av T i Promise<T> inte är en Example.
interface Example {
id: number
age: number
}
interface Promise <T> {
then <U> ( f: ( a: T) => U ) : Promise<U>
}
function f(s:Example){
return s.age
}
var p : Promise<{ id: number }>
p.then(f) // no type error (bad)
p.then(function(a){
f(a) // type error (good)
})
Jag undrar varför detta händer men också, tekniker för att mildra permissiv typkontroll i Typescript.
Om bivarians förklarar detta fenomen, varför uppstår då ett typfel när f används explicit? Varför finns det olika regler för förstaklassfunktioner jämfört med explicit användning?
Svar #1
Här är vad jag tror händer:
p.then(f) // no type error (bad)
Thär är{ id: number }then()deklareras för att ta ett argument av typen{id: number} => U- f har typen
Example => number Examplekan tilldelas{id: number}, såfär kompatibel med argumenttypen förthen()på grund av bivarians
Låt mig lägga till ett exempel till:
p.then(function(a : Example){
f(a)
})
Det kompilerar också utan fel, av samma anledning:
- argumentet för
then()har typenExample => number
Nu, varför kompilerar inte följande?
p.then(function(a){ f(a) // type error (good) })
- Jag antar att
ahärleds till att ha typen{id: number}(eftersom det enklaste att göra är att anta att det ärTfrån deklarationen avp) - så
fkallas med en inkompatibel argument här - eftersom
{id: number}inte kan tilldelasExamplesomfbehöver (ålder saknas).
Observera att felet inte handlar om argumentet för then(), utan om argumentet för f().
Nu, för den andra delen av frågan:
tekniker för att mildra permissiv typkontroll i Typescript.
Om du behöver korrekt typkontroll är IMO Typescript inte ett alternativ så länge osäker men "användbar" typkontroll förblir ett av dess uttryckliga designmål. Jag har hört att Scala, Haskell och OCaml alla har kompilatorer som riktar sig mot JavaScript nuförtiden (men jag har ingen aning om hur användbara de är).
Och den tredje delen av frågan:
Varför finns det olika regler för funktioner av första klass jämfört med explicit tillämpning?
För i det första fallet är argumentet en funktion, och i det andra fallet (som inte kompilerar) har argumentet typen {id : number}, vilket inte är en funktion. Bivarians är en ad hoc-regel som endast tillämpas när det behöver avgöras om en funktionstyp är kompatibel med en annan funktionstyp. Det första fallet kompilerar eftersom när den ser att then()-argumentet är okej enligt reglerna, går den inte ner i then()-implementeringen för att kontrollera hur det faktiskt kommer att fungera där. Det är det som gör den osäker.
