>[success] # 高級類型
>[danger] ##### 交叉類型
~~~
1.交叉類型:我們可以把現有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性,取多個類型的并集
簡單的說' 交叉類型是將多個類型合并為一個類型',用'&' 來表示
2.下面的案例是將兩個對象合并,并且返回合并后的對象
~~~
~~~
const mergFunc = <T,U>(arg1:T,age2:U):U&T=>{
let res = {} as U&T
res = Object.assign(arg1,age2)
return res
}
mergFunc({a:1},{b:2})
~~~
>[danger] ##### 聯合類型
~~~
1.聯合類型表示一個值可以是幾種類型之一,用'|' 來表示
~~~
~~~
const getLenFunc = (content:number|string)=>{
if (typeof content === 'string'){ return content.length}
else {return content.toString().length}
}
// getLenFunc(true) // 報錯 只能是string 或者是number類型中的一個
~~~
* 接口用聯合類型
~~~
1.如果一個值是聯合類型,我們只能訪問此聯合類型的所有類型里共有的成員
簡單的說'使用一個聯合類型的參數只能使用共有成員',下面案例中c雖然有age屬性,但是會報錯
只能使用他們的共有成員name
~~~
~~~
interface a {
name:string,
age:number
}
interface b {
name:string,
sex:string
}
// const c:(a|b) = {
// age:13,
// sex:'nan'
// } // 報錯
const c:(a|b) = {
name:'fff',
age:12,
sex:'w'
}
// c.age// 報錯
c.name
~~~
>[danger] ##### 類型守衛
~~~
1.第一種使用方法封裝 ,方法返回值的格式 是 '值' is '類型'
2.第二中是直接使用type of ,但只能針對"number","string","boolean"或"symbol",
這里的針對要解釋一下,首先type of 是js 的,所以 寫type of === ‘object’是可以的
,但是不會自帶自動后往后的判斷,下面案例為例'判斷了string'類型else 自動判斷就是
number 類型,如果是判讀是非這四種類型,else 還需要要自己處理
3.如果是類用instance of 作為類型保護
~~~
* 什么場景實用
~~~
const getRandomValue = (list:(string|number)[])=>{
const randomNumber = Math.random() * 10
if (randomNumber>5) return list[0]
else return list[1]
}
const item = getRandomValue([1,'w'])
// 直接這些寫會報錯
// 首先第一個問題是返回值的類型不確定是字符還是數字
// 數字是沒有length 屬性的所以這么寫的判斷ts 會報錯的
// if(item.length){
// console.log(item.length)
// }else{
// console.log(item.toFixed())
// }
// 解決第一種使用類型斷言
// 缺點 每一個item 都要使用對應的類型斷言
if ((item as string).length ){
console.log((item as string).length)
}else{
console.log((item as number).toFixed())
}
~~~
* 封裝方法--用戶自定義的類型守衛
(復雜情況用這種)
~~~
const getRandomValue = (list:(string|number)[])=>{
const randomNumber = Math.random() * 10
if (randomNumber>5) return list[0]
else return list[1]
}
const item = getRandomValue([1,'w'])
// 類型保護
// 注意 這里的is 可以是任意類型,可以是自己定義的接口類型
// 這里是因為需求是string 類型,并且返回相當于必須是一個boolean類型
function isString (value:number|string):value is string{
return typeof value === 'string'
}
if (isString(item)) {
console.log(item.length)
} else {
console.log(item.toFixed())
}
~~~
* typeof類型守衛(簡單情況用這種)
~~~
const getRandomValue = (list:(string|number)[])=>{
const randomNumber = Math.random() * 10
if (randomNumber>5) return list[0]
else return list[1]
}
const item = getRandomValue([1,'w'])
// 簡單的邏輯直接typeof 即可
// 比較的類型只能是"number","string","boolean"或"symbol"
if (typeof item === 'string') {
console.log(item.length)
} else {
console.log(item.toFixed())
}
~~~
* instanceof 類型保護
~~~
interface Padder {
getPaddingString(): string
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) { }
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) { }
getPaddingString() {
return this.value;
}
}
function getRandomPadder() {
return Math.random() < 0.5 ?
new SpaceRepeatingPadder(4) :
new StringPadder(" ");
}
// 類型為SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();
if (padder instanceof SpaceRepeatingPadder) {
padder; // 類型細化為'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
padder; // 類型細化為'StringPadder'
}
~~~
>[danger] ##### null 和undefined
~~~
1.在tsconfig.json 設置 'strictNullChecks':當你聲明一個變量時,它不會自動地包含null或undefined。
~~~
* 如果設置是true
~~~
let s = "foo";
s = null; // 錯誤, 'null'不能賦值給'string'
sn = undefined; // 錯誤,
~~~
* 如果設置false
~~~
let s = "foo";
s = null; //可以
sn = undefined; // 可以
~~~
* 如果設置了false 在可選參數的時候 是只能自動添加一個undefined
~~~
function f(x: number, y?: number) {
return x + (y || 0);
}
f(1, 2);
f(1);
f(1, undefined);
f(1, null); // error, 'null' is not assignable to 'number | undefined'
~~~
>[danger] ##### 類型斷言
~~~
1.如果編譯器不能夠去除null或undefined,你可以使用類型斷言手動去除。 語法是添加!后綴:
~~~
~~~
function broken(name: string | null): string {
function postfix(epithet: string) {
// return name.charAt(0) + '. the ' + epithet; // 報錯 有可能是null
return name!.charAt(0) + '. the ' + epithet; // 排除是null
}
name = name || "Bob";
return postfix("great");
}
~~~
>[danger] ##### 類型別名 -- type
~~~
1.'類型別名':給 這個類型起一個新的名字,簡單的理解 和js 一樣是給重復使用的變量起一個統一的名字調用,只不過ts規定的是類型
2.可以是原始值,聯合類型,元組以及其它任何你需要手寫的類型
~~~
~~~
type Name = string
type NameResolver = ()=>string
// 聯合類型
type NameOrResolver = Name | NameResolver
function getName(n: NameOrResolver): Name {
// 類型保護 所以else 會自動知道另外一個類型
if (typeof n === 'string') {
return n;
}
else {
return n();
}
}
let names:Name = 'w' // 相當于這個name 是string 類型
~~~
* 類型別名可以向接口一樣使用泛型
~~~
// 也可以像接口一樣使用泛型
type c<T> = {name:T,age:T}
~~~
* 利用類型別名生成樹型結構
~~~
1.這里要注意,child 字段必須是可選類型,否則就會讓你一直寫下去,而且這種自己用自己
只能出現在對象字段中,不能像下面這樣的寫法'type Yikes = Yikes[]; // error'
~~~
~~~
// 創建屬性結構的時候可以自己引用自己
type Childs<T>= {
current:T,
child?:Childs<T> // 可選參數
}
let tree:Childs<string> = {
current:'first',
child:{
current:'second',
child:{
current:'third'
}
}
}
~~~
* 交叉類型使用
~~~
type LinkedList<T> = T & { next: LinkedList<T> };
interface Person {
name: string;
}
var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;
~~~
>[danger] ##### 類型別名和接口的區別
~~~
1.'類型別名'不能被extends和implements(自己也不能extends和implements其它類型)
2.如果你無法通過接口來描述一個類型并且需要使用聯合類型或元組類型,這時通常會使用類型別名。
~~~
>[danger] ##### 字符串字面量 和 數字類型
~~~
1.指定具體字符串或數字
~~~
~~~
type Type= 'w'|1|'s'
// let type:Type = 6 //報錯 只能是 w 1 或者 s
~~~
>[danger] ##### 可辨識聯合
~~~
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
// 可辨識聯合
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
}
}
~~~
>[danger] ##### 完整類型檢查
~~~
1.這是時候其實我們代碼是有問題的如果傳入的是'Triangle' 類型整個代碼就會出現問題
~~~
~~~
type Shape = Square | Rectangle | Circle | Triangle;
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
}
// should error here - we didn't handle case "triangle"
}
~~~
* 解決這種幫助自動檢出有未用類型錯誤
~~~
1.啟用tsconfig--strictNullChecks并且指定一個返回值類型
~~~
~~~
function area(s: Shape): number { // error: returns number | undefined
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
}
}
~~~
~~~
2.使用never類型,編譯器用它來進行完整性檢查
~~~
~~~
function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
default: return assertNever(s); // error here if there are missing cases
}
}
~~~
- Vue--基礎篇章
- Vue -- 介紹
- Vue -- MVVM
- Vue -- 創建Vue實例
- Vue -- 模板語法
- Vue -- 指令用法
- v-cloak -- 遮蓋
- v-bind -- 標簽屬性動態綁定
- v-on -- 綁定事件
- v-model -- 雙向數據綁定
- v-for -- 只是循環沒那么簡單
- 小知識點 -- 計劃內屬性
- key -- 屬性為什么要加
- 案例說明
- v-if/v-show -- 顯示隱藏
- v-for 和 v-if 同時使用
- v-pre -- 不渲染大大胡語法
- v-once -- 只渲染一次
- Vue -- class和style綁定
- Vue -- filter 過濾器
- Vue--watch/computed/fun
- watch -- 巧妙利用watch思想
- Vue -- 自定義指令
- Vue -- $方法
- Vue--生命周期
- Vue -- 專屬ajax
- Vue -- transition過渡動畫
- 前面章節的案例
- 案例 -- 跑馬燈效果
- 案例 -- 選項卡內容切換
- 案例-- 篩選商品
- 案例 -- 搜索/刪除/更改
- 案例 -- 用computed做多選
- 案例 -- checked 多選
- Vue--組件篇章
- component -- 介紹
- component -- 使用全局組件
- component -- 使用局部組件
- component -- 組件深入
- component -- 組件傳值父傳子
- component -- 組件傳值子傳父
- component -- 子傳父語法糖拆解
- component -- 父組件操作子組件
- component -- is 動態切換組件
- component -- 用v-if/v-show控制子組件
- component -- 組件切換的動畫效果
- component -- slot 插槽
- component -- 插槽2.6
- component -- 組件的生命周期
- component -- 基礎組件全局注冊
- VueRouter--獲取路由參數
- VueRouter -- 介紹路由
- VueRouter -- 安裝
- VueRouter -- 使用
- VueRouter--router-link簡單參數
- VueRouter--router-link樣式問題
- VueRouter--router-view動畫效果
- VueRouter -- 匹配優先級
- vueRouter -- 動態路由
- VueRouter -- 命名路由
- VueRouter -- 命名視圖
- VueRouter--$router 獲取函數
- VueRouter--$route獲取參數
- VueRouter--路由嵌套
- VueRouter -- 導航守衛
- VueRouter -- 寫在最后
- Vue--模塊化方式結構
- webpack--自定義配置
- webpack -- 自定義Vue操作
- VueCli -- 3.0可視化配置
- VueCli -- 3.0 項目目錄
- Vue -- 組件升級篇
- Vue -- 組件種類與組件組成
- Vue -- 組件prop、event、slot 技巧
- Vue -- 組件通信(一)
- Vue -- 組件通信(二)
- Vue -- 組件通信(三)
- Vue -- 組件通信(四)
- Vue -- 組件通信(五)
- Vue -- 組件通信(六)
- Vue -- bus非父子組件通信
- Vue -- 封裝js插件成vue組件
- vue組件分裝 -- 進階篇
- Vue -- 組件封裝splitpane(分割面板)
- UI -- 正式封裝
- Vue -- iview 可編輯表格案例
- Ui -- iview 可以同時編輯多行
- Vue -- 了解遞歸組件
- UI -- 正式使用遞歸菜單
- Vue -- iview Tree組件
- Vue -- 利用通信仿寫一個form驗證
- Vue -- 使用自己的Form
- Vue -- Checkbox 組件
- Vue -- CheckboxGroup.vue
- Vue -- Alert 組件
- Vue -- 手動掛載組件
- Vue -- Alert開始封裝
- Vue -- 動態表單組件
- Vue -- Vuex組件的狀態管理
- Vuex -- 參數使用理解
- Vuex -- state擴展
- Vuex -- getters擴展
- Vuex--mutations擴展
- Vuex -- Action 異步
- Vuex -- plugins插件
- Vuex -- v-model寫法
- Vuex -- 更多
- VueCli -- 技巧總結篇
- CLI -- 路由基礎
- CLI -- 路由升級篇
- CLI --異步axios
- axios -- 封裝axios
- CLI -- 登錄寫法
- CLI -- 權限
- CLI -- 簡單權限
- CLI -- 動態路由加載
- CLI -- 數據性能優化
- ES6 -- 類的概念
- ES6類 -- 基礎
- ES6 -- 繼承
- ES6 -- 工作實戰用類數據管理
- JS -- 適配器模式
- ES7 -- 裝飾器(Decorator)
- 裝飾器 -- 裝飾器修飾類
- 裝飾器--修飾類方法(知識擴展)
- 裝飾器 -- 裝飾器修飾類中的方法
- 裝飾器 -- 執行順序
- Reflect -- es6 自帶版本
- Reflect -- reflect-metadata 版本
- 實戰 -- 驗證篇章(基礎)
- 驗證篇章 -- 搭建和目錄
- 驗證篇章 -- 創建基本模板
- 驗證篇章 -- 使用
- 實戰 -- 更新模型(為了迎合ui升級)
- 實戰 -- 模型與接口對接
- TypeSprict -- 基礎篇章
- TS-- 搭建(一)webpack版本
- TS -- 搭建(二)直接使用
- TS -- 基礎類型
- TS -- 枚舉類型
- TS -- Symbol
- TS -- interface 接口
- TS -- 函數
- TS -- 泛型
- TS -- 類
- TS -- 類型推論和兼容
- TS -- 高級類型(一)
- TS -- 高級類型(二)
- TS -- 關于模塊解析
- TS -- 聲明合并
- TS -- 混入
- Vue -- TS項目模擬
- TS -- vue和以前代碼對比
- TS -- vue簡單案例上手
- Vue -- 簡單弄懂VueRouter過程
- VueRouter -- 實現簡單Router
- Vue-- 原理2.x源碼簡單理解
- 了解 -- 簡單的響應式工作原理
- 準備工作 -- 了解發布訂閱和觀察者模式
- 了解 -- 響應式工作原理(一)
- 了解 -- 響應式工作原理(二)
- 手寫 -- 簡單的vue數據響應(一)
- 手寫 -- 簡單的vue數據響應(二)
- 模板引擎可以做的
- 了解 -- 虛擬DOM
- 虛擬dom -- 使用Snabbdom
- 閱讀 -- Snabbdom
- 分析snabbdom源碼 -- h函數
- 分析snabbdom -- init 方法
- init 方法 -- patch方法分析(一)
- init 方法 -- patch方法分析(二)
- init方法 -- patch方法分析(三)
- 手寫 -- 簡單的虛擬dom渲染
- 函數表達解析 - h 和 create-element
- dom操作 -- patch.js
- Vue -- 完成一個minVue
- minVue -- 打包入口
- Vue -- new實例做了什么
- Vue -- $mount 模板編譯階段
- 模板編譯 -- 分析入口
- 模板編譯 -- 分析模板轉譯
- Vue -- mountComponent 掛載階段
- 掛載階段 -- vm._render()
- 掛載階段 -- vnode
- 備份章節
- Vue -- Nuxt.js
- Vue3 -- 學習
- Vue3.x --基本功能快速預覽
- Vue3.x -- createApp
- Vue3.x -- 生命周期
- Vue3.x -- 組件
- vue3.x -- 異步組件???
- vue3.x -- Teleport???
- vue3.x -- 動畫章節 ??
- vue3.x -- 自定義指令 ???
- 深入響應性原理 ???
- vue3.x -- Option API VS Composition API
- Vue3.x -- 使用set up
- Vue3.x -- 響應性API
- 其他 Api 使用
- 計算屬性和監聽屬性
- 生命周期
- 小的案例(一)
- 小的案例(二)-- 泛型
- Vue2.x => Vue3.x 導讀
- v-for 中的 Ref 數組 -- 非兼容
- 異步組件
- attribute 強制行為 -- 非兼容
- $attrs 包括 class & style -- 非兼容
- $children -- 移除
- 自定義指令 -- 非兼容
- 自定義元素交互 -- 非兼容
- Data選項 -- 非兼容
- emits Option -- 新增
- 事件 API -- 非兼容
- 過濾器 -- 移除
- 片段 -- 新增
- 函數式組件 -- 非兼容
- 全局 API -- 非兼容
- 全局 API Treeshaking -- 非兼容
- 內聯模板 Attribute -- 非兼容
- key attribute -- 非兼容
- 按鍵修飾符 -- 非兼容
- 移除 $listeners 和 v-on.native -- 非兼容
- 在 prop 的默認函數中訪問 this -- ??
- 組件使用 v-model -- 非兼容
- 渲染函數 API -- ??
- Slot 統一 ??
- 過渡的 class 名更改 ???
- Transition Group 根元素 -- ??
- v-if 與 v-for 的優先級對比 -- 非兼容
- v-bind 合并行為 非兼容
- 監聽數組 -- 非兼容