網站搜尋

TypeScript 中協變/逆變類型分配的意外行為


我對 TypeScript 是新手,並且我發現了一些關於協變/逆變行為的意外情況。

這裡有一段程式碼片段:

interface Func1 {
    (): { prop1: string }
}

// assignment similar to covariance
var f1: Func1 = function () { return { prop1: "", prop2: 0 }; }

interface Func2 {
    ({prop1: string, prop2: number}): void;
}

// assignment similar to contra-variance
var f3: Func3 = function (a: { prop1: string }) { }

interface Func3 {
    ({prop1: string}): void;
}

// assignment violates principle of contra-variance.
// expect a compiling error but there isn't.
var f3: Func3 = function (a: { prop1: string, prop2: number }) { alert(a.prop2); }

// here occurs a non-existing field accessing
// it might be unexpected and was possible to be eliminated by static checking on assignment to 'f3'.
f3({ prop1: "" }); 

將值指派給 f1 是可以的,因為匿名函數的返回值可以指派給 Func1 的返回值類型。

將值指派給 f2 也沒問題,因為傳給 Func2 類型的參數可以指派給匿名函數的參數 'a'。

分配給 f3 應該會失敗,因為傳給 Func3 類型的參數無法分配給匿名函數的參數 'a',所以我預期編譯器會報錯,但實際上並沒有。

這在呼叫 f3 時導致了意外的存取違規。

我的問題是,這種行為是預期的,還是 TypeScript 設計/實現上的缺陷?

答案#1

// 賦值違反了反變原則。 /預期會有編譯錯誤,但沒有。

這是常見問題,並且有文檔記錄: https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Type%20Compatibility.md#function-argument-bivariance

基本上,它允許方便地添加事件監聽器(這是一個相當常見的 JavaScript 任務,如果語言將安全性推得更高,移植到 TypeScript 會變得困難)。