TS型變與對象類型進階

?子類型:給定兩個類型A和B,假設B是A的子類型,那么在需要A的地方都可以放心使用B。計作 A <: B (A是B的子類型)。

超類型正好與子類型相反。A >: B (A是B的超類型)。

1 TS 類型

可賦值性指在判斷需要B類型的地方是否可以使用A類型。當A <: B 時,是滿足可賦值性的,不過TS有兩處例外的地方:

1)當A是any時,可賦值給B類型。

function testFun(b:boolean) {console.log(b); // 2
}
let a:any = 2;
testFun(a);

TS 這樣做是為了方便與JS代碼互操作。

2)B 是枚舉類型,且至少有一個成員是number類型,而且A是數字。

這是安全性的一大隱患,盡量不要這么操作。

1.1 型變

如果想要保證A可賦值給B對象,那么A對象的每個屬性都必須<: B 對象對應的屬性。此時,我們說TS對結構(對象和類)的屬性類型進行了協變。

type User = {name: string,money?: number
}
type VipUser = {name: string,money: number
}let user: User = {name: "牛",
}
let vipUser:VipUser = {name: "張",money: 1000
}user = vipUser;
vipUser = user; //ERROR Type User is not assignable to type VipUser

不變

只能是T

逆變

可以是 >: T

協變

可以是 <: T

雙變

可以是 <: T或 >: T

表 型變的四種方式

在TS中,每個復雜類型的成員都會進行協變,包括函數的返回類型。不過有個例外:函數的參數類型進行逆變。

1.1.1 函數的型變

如果函數A的參數數量小等于函數B的參數數量,且同時滿足下述條件,那么函數A是函數B的子類型:

1)函數A的this類型未指定,或者>:函數B的this類型。

2)函數A的各個參數的類型 >: 函數B對應參數。

3)函數A的返回類型<: 函數B的返回類型。

class Person {constructor(public sex: number) {}
}
class Man extends Person{constructor(public name: string,sex: number) {super(sex);}
}type FunA = (this: Person) => void; // 子類型
type FunB = (this: Man) => void; // 父類型let person:Person = new Person(1);
let man:Man = new Man("李",1);let funA:FunA = function () {console.log(this);}
let funB:FunB = function () {console.log(this);}funA.bind(person)();
//funB.bind(person); // ERRORfunA.bind(man)();
funB.bind(man)();funB = funA;
// funA = funB; // ERROR

函數的協變似乎有些特殊,在我們常規認知中,子類型的作用范圍窄于父類型。但是在上面例子中,作為子類型的A函數類型,比父類B可綁定的對象類型更廣。子類的唯一定義是:在需要父類的地方可以放心使用子類。上面代碼在使用B的地方,可以放心使用A,而使用A的地方不能放心使用B。

type FunA = (this:any) => void; // 子類
type FunB = (this:Man) => void; // 父類let funA:FunA = function () {console.log(this);};
let funB:FunB = function () {console.log(this);};funA.bind(man)();
funB.bind(man)();// funB.bind(person)(); // ERROR
funA.bind(person)();let fun1: FunA = funB;
let fun2: FunB = funA;

上面代碼展示了一個特殊情況:當this為any類型(或未指定時)。這里符合第一個條件。

type FunA = (person: Person) => void; // 子類
type FunB = (man: Man) => void; // 父類let funA:FunA = function(person:Person) {console.log("funA:" + person.sex);}
let funB:FunB = function (man:Man) {console.log("funB:" + man.name);}function testFunA(fun: (person: Person) => void) {}
function testFunB(fun: (man: Man) => void) {let man = new Man("張",1);fun(man);
}testFunA(funA);
// testFun(funB); // ERROR
testFunB(funA);
testFunB(funB);

1.2 類型擴展

一般來說,TS在推導類型時會放寬要求,故意推導出一個更寬泛的類型。聲明變量時如果允許以后修改變量的值,變量的類型將拓展,從字面量擴大到包含該字面量的基類型:

let a = “x”; // string

let b = 1; // number

let c = {x: 1}; // {x: number}

聲明為不可變的變量時:

const a = “x”; // “x”

可以通過顯示注解類型,防止類型被擴展:

let a: “x” = “x”; // “x”

如果使用let或var 重新為不可變的變量賦值,將自動擴展:

const a = “x”; // “x”

let b = a; // string

const 會禁止類型拓寬,還遞歸把成員設為readonly:

let x = {a: “t”,b: {x: 12}} as const; // {readonly a: “t”,readonly b: {readonly x:12}}

1.2.1 多余屬性檢查

TS嘗試把新鮮對象字面量類型T賦值給另一個類型U,如果T有U不存在的屬性,則報錯。

新鮮對象:TS直接從字面量推導出的類型。如果把對象字面量賦值給變量或者對象字面量有斷言,則其不是新鮮對象,而是常規對象。

type ObjType = {name: string
}let obj1:ObjType = {name: ""
}
let obj2:ObjType = {name: "",type: 1 // 報錯
} // 為新鮮對象
let obj3:ObjType = {name: "",type: 1
} as ObjType // true 有類型斷言function fun(obj: ObjType) {}
let obj4 = {name: "",type: 1
}
fun(obj4); // true 已被賦值給變量,為常規對象
fun({name: "",type: 1 // 報錯
}) // 為新鮮變量

2 對象類型進階

2.1 類型運算符

我們可以像獲取對象屬性值一樣獲取類型的某個屬性類型 (必須用方括號,不能用點號):

type ObjType = {name: string,user: {type: number,name: string}
};
type UserType = ObjType["user"]; // {type: number,name:string}

keyof 運算符獲取對象所有鍵的類型,合并為一個字符串字面量類型,以上面的ObjType為例:

type ObjTypeKeysType = keyof ObjType; // "name" | "user"
type UserTypeKeysType = keyof UserType; // "type" | "name"

2.2 映射類型

TS中,我們可以為類型定義索引簽名[key:T] : U,該類型的對象可能有更多的鍵,鍵的類型為T,值的類型為U。其中T必須為number或string。

而映射類型則在索引簽名的基礎上,為key做了限制。這讓類型更安全:

type IndexType = {[K: string]: string
} // 只限定了key 為 string類型type MappedType = {[K in "key1" | "key2"]: string
} // 限定了屬性必須有且只有“key1”和“key2”let indexType: IndexType = {"a": "","b": ""
}; //
let mappedType: MappedType = {"key1": "","key2": ""
}
let mappedType2:MappedType = {"key1": ""
} // 報錯 Property key2 is missing in type { key1: string; } but required in type MappedType

2.2.1 Record類型

TS內置的Record類型用于描述有映射關系的對象。是使用映射類型實現的。

type RecordType = Record<"a"|"b",1 | 2 | 3>let r1: RecordType = {"a": 1,"b": 1,
}
let r2: RecordType = {"a": 1,"b": 5
} // 報錯 Type 5 is not assignable to type 1 | 2 | 3
let r3: RecordType = {"a": 1
} // 報錯 Property b is missing in type { a: 1; } but required in type RecordType

2.3 伴生對象模式

TS的類型和值分別在不同的命名空間。在同一作用域中,我們可以有同名的類型和值。在語義上歸屬同一個名稱的類型和值放在一起,其次,使用方可以一次性導入二者。

type User = {name: string
}
let User = {createUser(name:string):User {console.log("這是值創建的");return {name: name}}
}
let user:User = User.createUser("hmf");

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210092.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210092.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210092.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用cmake構建Qt6.6的qt quick項目,添加應用程序圖標的方法

最近&#xff0c;在學習qt的過程中&#xff0c;遇到了一個難題&#xff0c;不知道如何給應用程序添加圖標&#xff0c;按照網上的方法也沒有成功&#xff0c;后來終于自己摸索出了一個方法。 1、準備一張圖片作為圖標&#xff0c;保存到工程目錄下面&#xff0c;如logo.ico。 …

Qt 編譯fcitx-qt5 插件支持中文輸入法

前言 在Linux系統上會遇到Qt開發的程序無法輸入中文的情況&#xff0c;原因就是因為輸入法框架是采用的fcitx&#xff0c;而不是ibus&#xff0c;Qt默認只支持ibus輸入法框架。在Qt/5.15.2/gcc_64/plugins/platforminputcontexts/路徑下可以看到&#xff0c;只有libibusplatfo…

引入JavaScript文件的5種方式

在HTML文件中&#xff0c;可以使用以下5種方式引入JavaScript文件&#xff1a; 1.內聯方式&#xff08;Inline&#xff09;&#xff1a; 在HTML的<script>標簽中直接編寫JavaScript代碼。 示例&#xff1a; <script>// JavaScript代碼 </script>2.外部文件…

Python Selenium3 簡單操作進行百度搜索

當前環境&#xff1a;Win10 Python3.7 selenium3.141.0&#xff0c;urllib31.26.2 from selenium import webdriver import timeif __name__ __main__:# Chrome 路徑CHROME_PATH rC:\Program Files (x86)\65.0.3312.0\chrome-win32\chrome.exe# ChromeDriver 路徑CHROMEDR…

mybatis的快速入門以及spring boot整合mybatis(二)

需要用到的SQL腳本&#xff1a; CREATE TABLE dept (id int unsigned PRIMARY KEY AUTO_INCREMENT COMMENT ID, 主鍵,name varchar(10) NOT NULL UNIQUE COMMENT 部門名稱,create_time datetime DEFAULT NULL COMMENT 創建時間,update_time datetime DEFAULT NULL COMMENT 修改…

極智芯 | 解讀國產AI算力 靈汐產品矩陣

歡迎關注我的公眾號 [極智視界],獲取我的更多經驗分享 大家好,我是極智視界,本文分享一下 解讀國產AI算力 靈汐產品矩陣。 邀您加入我的知識星球「極智視界」,星球內有超多好玩的項目實戰源碼和資源下載,鏈接:https://t.zsxq.com/0aiNxERDq [系列聲明:最近寫了十余篇 &…

低多邊形建筑3D模型紋理貼圖

在線工具推薦&#xff1a; 3D數字孿生場景編輯器 - GLTF/GLB材質紋理編輯器 - 3D模型在線轉換 - Three.js AI自動紋理開發包 - YOLO 虛幻合成數據生成器 - 三維模型預覽圖生成器 - 3D模型語義搜索引擎 當談到游戲角色的3D模型風格時&#xff0c;有幾種不同的風格&#xf…

基于SSM的鞍山職業技術學院圖書借閱管理系統

文章目錄 項目介紹主要功能截圖:部分代碼展示設計總結項目獲取方式?? 作者主頁:超級無敵暴龍戰士塔塔開 ?? 簡介:Java領域優質創作者??、 簡歷模板、學習資料、面試題庫【關注我,都給你】 ??文末獲取源碼聯系?? 項目介紹 基于SSM的鞍山職業技術學院圖書借閱管理…

樹莓派CSI攝像頭在新系統(23年12月)中的不用設置了,沒有開關,也沒有raspistill

網上都是老信息&#xff0c;用的raspistill命令&#xff0c;至少新系統沒有這個東西了&#xff0c;也不會在sudo raspi-config里面也沒有攝像頭的開關了。 ls /dev/video* 能看到攝像頭video0&#xff0c;但是vcgencmd get_camera supported0&#xff0c; detected0&#xff0…

【python】閉包和裝飾器

前置知識&#xff1a; 函數的本質就是變量名可以把函數作為參數傳遞&#xff0c;例如&#xff1a; def func():print("我是func")# 接收的fn是個函數 def handle(fn): # 調用函數fn()handle(func)可以把函數作為返回值返回&#xff0c;例如 def func():def func2(…

CPU的三大調度

計算機系統中的調度可以分為不同層次&#xff0c;包括作業調度、內存調度和進程調度。這三種調度分別負責管理和優化計算機系統中不同層次的資源分配和執行順序。 高級調度&#xff1a;作業調度&#xff08;Job Scheduling&#xff09;&#xff1a; 作業調度是指對提交到計算…

了解c++11中的新增

一&#xff0c;統一的初始化列表 在引入c11后&#xff0c;我們得出計劃都可以用初始化列表進行初始化。 C11 擴大了用大括號括起的列表 ( 初始化列表 ) 的使用范圍&#xff0c;使其可用于所有的內置類型和用戶自 定義的類型&#xff0c; 使用初始化列表時&#xff0c;可添加等…

Vue學習計劃-Vue2--VueCLi(二)vuecli腳手架創建的項目內部主要文件分析

1. 文件分析 1. 補充&#xff1a; 什么叫單文件組件&#xff1f; 一個文件中只有一個組件 vue-cli創建的項目中&#xff0c;.vue的文件都是單文件組件&#xff0c;例如App.vue 2. 進入分析 1. package.json: 項目依賴配置文件&#xff1a; 如圖&#xff0c;我們說主要的屬性…

性能測試經典面試題(帶答案)!

概述一下性能測試流程&#xff1f; 1.分析性能需求。挑選用戶使用最頻繁的場景來測試。確定性能指標&#xff0c;比如&#xff1a;事務通過率 為100%&#xff0c;TOP99%是5秒&#xff0c;最大并發用戶為1000人&#xff0c;CPU和內存的使用率在70%以下2.制定性能測試計劃&…

Ubuntu20.04使用cephadm部署ceph集群

文章目錄 Requirements環境安裝Cephadm部署Ceph單機集群引導&#xff08;bootstrap&#xff09;建立新集群 管理OSD列出可用的OSD設備部署OSD刪除OSD 管理主機列出主機信息添加主機到集群從集群中刪除主機 部署Ceph集群 Cephadm通過在單個主機上創建一個Ceph單機集群&#xff0…

游戲開發庫

整理了38個Python游戲開發庫 https://zhuanlan.zhihu.com/p/505095419 https://zhuanlan.zhihu.com/p/262012936 2023 年最佳游戲引擎推薦 https://zhuanlan.zhihu.com/p/624771157 十大開源游戲引擎深入比較之美 https://blog.51cto.com/u_15273495/2915535 panda3d https:…

【EI會議征稿中】第三屆網絡安全、人工智能與數字經濟國際學術會議(CSAIDE 2024)

第三屆網絡安全、人工智能與數字經濟國際學術會議&#xff08;CSAIDE 2024&#xff09; 2024 3rd International Conference on Cyber Security, Artificial Intelligence and Digital Economy 第二屆網絡安全、人工智能與數字經濟國際學術會議&#xff08;CSAIDE 2023&…

Verilog基礎:寄存器輸出的兩種風格

相關文章 Verilog基礎https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 Verilog中的寄存器操作一般指的是那些對時鐘沿敏感而且使用非阻塞賦值的操作。例如狀態機中的狀態轉移&#xff0c;實際上就是一種寄存器操作&#xff0c;因為這相…

聽GPT 講Rust源代碼--src/tools(10)

File: rust/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs 在Rust源代碼中&#xff0c;rust-analyzer是一個Rust語言的IDE插件和代碼分析器。其中&#xff0c;generate_is_empty_from_len.rs是rust-analyzer中的一個處理程序&#x…

終于有人把tcp、http、rpc和grpc總結完整了

隨著微服務的迅速發展&#xff0c;各大互聯網企業也投入到微服務的?使用種。微服務最大的特點是&#xff0c;跨進程、跨服務、跨語言之間的調用&#xff0c;使得我們能夠像調用本地類、函數一樣。當微服務具備該特點&#xff0c;將我們復雜的業務拆分成不同的服務&#xff0c;…