回傳值型別
在 JavaScript 中,我們知道一個函式可以沒有顯式 return,此時函式的回傳值應該是 undefined:
function fn() {
// TODO
}
console.log(fn()); // => undefined
需要注意的是,在 TypeScript 中,如果我們顯式宣告函式的回傳值型別為 undfined,將會得到如下所示的錯誤提醒,
function fn(): undefined { // ts(2355) A function whose declared type is neither 'void' nor 'any' must return a value
// TODO
}
此時,正確的做法是使用 void 型別來表示函式沒有回傳值的型別(這是“廢柴” void 型別唯一有用的場景),示例如下:
function fn1(): void {
}
fn1().doSomething(); // ts(2339) Property 'doSomething' does not exist on type 'void'
我們可以使用類似定義箭頭函式的語法來表示函式型別的引數和回傳值型別,此時=> 型別僅僅用來定義一個函式型別而不用實作這個函式,
需要注意的是,這里的
=>與 ES6 中箭頭函式的=>有所不同,TypeScript 函式型別中的=>用來表示函式的定義,其左側是函式的引數型別,右側是函式的回傳值型別;而 ES6 中的=>是函式的實作,
在物件(即介面型別)中,除了使用這種宣告語法,我們還可以使用類似物件屬性的簡寫語法來宣告函式型別的屬性,如:
interface Entity {
add: (a: number, b: number) => number;
del(a: number, b: number): number;
}
const entity: Entity = {
add: (a, b) => a + b,
del(a, b) {
return a - b;
},
};
在某種意義上來說,這兩種形式都是等價的,但是很多時候,我們不必或者不能顯式地指明回傳值的型別,這就涉及可預設和可推斷的回傳值型別的講解,
可預設和可推斷的回傳值型別
幸運的是,函式回傳值的型別可以在 TypeScript 中被推斷出來,即可預設,
函式內是一個相對獨立的背景關系環境,我們可以根據入參對值加工計算,并回傳新的值,從型別層面看,我們也可以通過型別推斷加工計算入參的型別,并回傳新的型別,示例如下:
function computeTypes(one: string, two: number) {
const nums = [two];
const strs = [one]
return {
nums,
strs
} // 回傳 { nums: number[]; strs: string[] } 的型別
}
請記住:這是一個很重要也很有意思的特性,函式回傳值的型別推斷結合泛型可以實作特別復雜的型別推斷,比如 Redux Model 中 State、Reducer、Effect 型別的關聯,
一般情況下,TypeScript 中的函式回傳值型別是可以預設和推斷出來的,但是有些特例需要我們顯式宣告回傳值型別,比如 Generator 函式的回傳值,
Generator 函式的回傳值
ES6 中新增的 Generator 函式在 TypeScript 中也有對應的型別定義,
Generator 函式回傳的是一個 Iterator 迭代器物件,我們可以使用 Generator 的同名介面泛型或者 Iterator 的同名介面泛型表示回傳值的型別(Generator 型別繼承了 Iterator 型別),示例如下:
type AnyType = boolean;
type AnyReturnType = string;
type AnyNextType = number;
function *gen(): Generator<AnyType, AnyReturnType, AnyNextType> {
const nextValue = yield true; // nextValue 型別是 number,yield 后必須是 boolean 型別
return `${nextValue}`; // 必須回傳 string 型別
}
注意:TypeScript 3.6 之前的版本不支持指定 next、return 的型別,所以在某些有點歷史的代碼中,我們可能會看到 Generator 和 Iterator 型別不一樣的表述,
引數型別
關于 JS 中函式的引數,在es6之后,統共可以分為:可選引數、默認引數、剩余引數 幾個特性,
可選引數和默認引數
在實際作業中,我們可能經常碰到函式引數可傳可不傳的情況,當然 TypeScript 也支持這種函式型別表達,如下代碼所示:
function log(x?: string) {
return x;
}
log(); // => undefined
log('hello world'); // => hello world
在上述代碼中,我們在型別標注的:前添加?表示 log 函式的引數 x 就是可預設的,
也就是說引數 x 的型別可能是 undefined(第 5 行呼叫 log 時不傳入實參)型別或者是 string 型別(第 6 行呼叫 log 傳入 'hello world' 實參),那是不是意味著可預設和型別是 undefined 等價呢?
function log(x?: string) {
console.log(x);
}
function log1(x: string | undefined) {
console.log(x);
}
log();
log(undefined);
log1(); // ts(2554) Expected 1 arguments, but got 0
log1(undefined);
顯而易見:這里的 ?: 表示引數可以預設、可以不傳,但如果傳則一定是string型別,也就是說呼叫函式時,我們可以不顯式傳入引數,但是,如果我們宣告了引數型別為 xxx | undefined,就表示函式引數是不可預設且型別必須是 xxx 或者 undfined,
因此,在上述代碼中,log1 函式如果不顯示傳入函式的引數,TypeScript 就會報一個 ts(2554) 的錯誤,即函式需要 1 個引數,但是我們只傳入了 0 個引數,
在 ES6 中支持函式默認引數的功能,而 TypeScript 會根據函式的默認引數的型別來推斷函式引數的型別,示例如下:
function log(x = 'hello') {
console.log(x);
}
log(); // => 'hello'
log('hi'); // => 'hi'
log(1); // ts(2345) Argument of type '1' is not assignable to parameter of type 'string | undefined'
在上述示例中,根據函式的默認引數 'hello' ,TypeScript 推斷出了 x 的型別為 string | undefined,
當然,對于默認引數,TypeScript 也可以顯式宣告引數的型別(一般默認引數的型別是引數型別的子集時,我們才需要這么做),不過,此時的默認引數只起到引數默認值的作用,如下代碼所示:
function log1(x: string = 'hello') {
console.log(x);
}
// ts(2322) Type 'string' is not assignable to type 'number'
function log2(x: number = 'hello') {
console.log(x);
}
log2();
log2(1);
log2('1'); // ts(2345) Argument of type '"1"' is not assignable to parameter of type 'number | undefined'
上例函式 log2 中,我們顯式宣告了函式引數 x 的型別為 number,表示函式引數 x 的型別可以不傳或者是 number 型別,因此,如果我們將默認值設定為字串型別,編譯器就會拋出一個 ts(2322) 的錯誤,
同理,如果我們將函式的引數傳入了字串型別,編譯器也會拋出一個 ts(2345) 的錯誤,
請再次注意:函式的默認引數型別必須是引數型別的子型別:
function log3(x: number | string = 'hello') {
console.log(x);
}
在上述代碼中,函式 log3 的函式引數 x 的型別為可選的聯合型別 number | string,但是因為默認引數字串型別是聯合型別 number | string 的子型別,所以 TypeScript 也會檢查通過,
剩余引數
在 ES6 中,JavaScript 支持函式引數的剩余引數,它可以把多個引數收集到一個變數中,同樣,在TypeScript 中也支持這樣的引數型別定義,如下代碼所示:
function sum(...nums: number[]) {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2); // => 3
sum(1, 2, 3); // => 6
sum(1, '2'); // ts(2345) Argument of type 'string' is not assignable to parameter of type 'number'
在上述代碼中,sum 是一個求和的函式,...nums將函式的所有引數收集到了變數 nums 中,而 nums 的型別應該是 number[],表示所有被求和的引數是數字型別,因此,sum(1, '2') 拋出了一個 ts(2345) 的錯誤,因為引數 '2' 并不是 number 型別,
如果我們將函式引數 nums 聚合的型別定義為 (number | string)[],如下代碼所示:
function sum(...nums: (number | string)[]): number {
return nums.reduce<number>((a, b) => a + Number(b), 0);
}
sum(1, '2', 3); // 6
那么,函式的每一個引數的型別就是聯合型別 number | string,因此 sum(1, '2', 3) 的型別檢查也就通過了,
typescript中的常見報錯:
ts(2322)是一個靜態型別檢查的錯誤,在注解的型別和賦值的型別不同的時候就會拋出這個錯誤- ts(2355) :簡單來說就是:函式必須有一個回傳值(報錯翻譯:宣告型別既不是
void也不是any的函式必須回傳一個值) - ts(2339): 在TypeScript中如果按JS的方式去獲取物件屬性時,可能會遇到,它表示Typescript在執行代碼檢查時在該物件沒有定義相應屬性,解決方法有 —— 直接設定物件為
any、物件斷言為any、將屬性.獲取方式改為陣列式獲取三種 - ts(2345):引數型別與預期不符
- ts(2554):引數個數與預期不符
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/298137.html
標籤:其他
上一篇:HTML+CSS+JS實作 ??酷炫彩虹旋轉隧道特效??
下一篇:cgb2107-day09
