1、基礎類型
let a: (number | String) = new String('123')
// String 可以是 new String/ '' 形式, string 則不行
2、數組
數組特殊需求
數組可能是number、string 類型
數組中有一個元素可有可無
數組中前面固定, 后面可以隨意添加
// 數組可能是number、string 類型
let arr: Array<number|string> = []
arr = ['123',1,2,3]
// 數字類型的數組
let arr1: number[] = []
// 數組中有一個元素可有可無
let arr2: [number, string?] = [1] // 元組
// 數組中前面固定, 后面可以隨意添加
let arr3: [number, string?, ...(string|number)[]] = [1,'',123]
3、對象
基本使用
// 基本使用
let obj: {} = { a: 123, c: 123 } // 這樣使用和 any 差不多意思,意義不是很大
// 一般使用
let obj: { x: 123, y: number} = { x: 123, y: 123}
對象特殊需求
規定鍵名是一個數字
屬性可有可無
固定某幾個屬性, 其他屬性隨便添加
// 規定鍵名是一個數字
let obj1: { [key: number]: number } = { 1: 1 }
// 屬性可有可無
let obj: { x: 123, y: number, z?: number} = { x: 123, y: 123}
// 固定某幾個屬性, 其他屬性隨便添加
let obj1: { x: 123, y: number, [key: number]: number|{} } = { x: 123, y: 1, 1: {}}
4、 函數
基本使用
// 直接定義一個函數的參數和返回
function f1(a:string): string {}
// 定義一個函數變量
let f2:(a:string)=>string = function(a){}
函數特殊需求
參數默認值和可選
this 處理
剩余參數處理
根據不同類型參數,有不同返回
// 參數和可選
function f1(a: number, b?: number) {}
// 剩余參數可選
function f1(a: number, b?: number, ...arg: (number|string)[]):any {}
// 參數默認值
function f1(a = 3) {}
// this 處理
function f3(this:void, a:number) {}
// 根據不同類型參數,有不同返回(重載)
5、類

class Jsclass {
public a: number = 123
static target: number = 123
readonly c = 2
f2(a: string): string
f2(a: string) {
return a
}
private f1() {
console.log(1)
}
}
// Jsclass 可以當作類型使用
let obj: Jsclass = {
a: 1,
c: 2,
f2: function(a) { return a }
}
6、特殊類型與高級類型
unknown 和 any
- any 和 unknow 類型都可以分配任何值
- Unkown 相當于更安全的 any, unknown 類型只能拿賦值給 unknown 或者 any
let value: unknown = {}
let value2: any = '123'
function f1(a:any):any {
}
let value3: string = value2 // any可以任意復制,會有問題
let vlaue4: string = vlaue // 這里報錯, unknown 只能復制給 any/unknown
never
- never 代表永遠不會出現
- never 類型的變量可以賦值給任何東西, 但是 never 類型不能有任何值
- 錯誤類型,或者永遠沒有結果的返回值可以用 never
function throwError():never { throw new Error() }
聯合類型
let a: string|number
交叉類型
class obj1class { a: number }
class obj2class { b: number }
let obj3: obj1class & obj2class { a: 1, b: 2 }
7、接口與type

聲明合并: 聲明兩個一樣的接口名則會合并
type
- type 關鍵字用于給一個類型一個命名,可以用于各種類型的定義
- 常用于基礎類型和聯合,交叉類型
type aString = string | number | number[]
type obj1 = { a: number }
type obj2 = { b: string }
//繼承(合并)
type objAll = obj1 & obj2
// 函數
type f1 = (a: string) => string
let b: aString = [1,2,3]
interface
- interface 意思為接口, 區別于type, 這是定義了一個可繼承的接口
- 常用于類,對象的定義
// 函數、對象、 類、 數組
// 對象接口
interface ojb3 {
type: { a1: number }
type2?: string,
[propName:string]: any
}
// 函數
function f2(a:obj3) {
console.log(a.type.a1)
}
f2({type:{a1:23}})
interface fn {
(a:number, b:number): string
}
let ff5: fn = function(a,b) {
return ''
}
// 對象
interface obj5 {
a: 123,
f1: (a:number) => number
}
let obj: obj5 = { a:123, f1: (a: number) => {return a} }
// 類 - implement
interface person {
age: number,
eat(food: string): string
}
class Mary implements person {
age: number
eat(food: string): string
constructor(age: number) {
this.age = age
}
eat(food: string) {
return "123"
}
}
// 數組
interface arr{
[propname: number]: string
}
let arr1:arr = ['1','123']
// 繼承
interface interObj {
num: number
}
interface interObj2 {
str: string
}
interface interObj3 extends interObj,interObj2 {
arr: number[]
}
let obj: interObj3 = {
num:1,
str:"1",
arr: [1,2]
}
8. 泛型和斷言
泛型 就是不知道是啥類型,在像C#和Java這樣的語言中,可以使用泛型來創建可重用的組件,一個組件可以支持多種類型的數據。 這樣用戶就可以以自己的數據類型來使用組件。
泛型之Hello World
不用泛型的話,這個函數可能是下面這樣:
function identity(arg: number|any): number|any {
return arg;
}
使用any類型會導致這個函數可以接收任何類型的arg參數,這樣就丟失了一些信息:傳入的類型與返回的類型應該是相同的。如果我們傳入一個數字,我們只知道任何類型的值都有可能被返回。
因此,我們需要一種方法使返回值的類型與傳入參數的類型是相同的。 這里,我們使用了 類型變量,它是一種特殊的變量,只用于表示類型而不是值。
function identity<T>(arg: T): T {
return arg;
}
我們定義了泛型函數后,可以用兩種方法使用。 第一種是,傳入所有的參數,包含類型參數:
let output = identity<string>("myString"); // type of output will be 'string'
這里我們明確的指定了T是string類型,并做為一個參數傳給函數,使用了<>括起來而不是()。
第二種方法更普遍。利用了類型推論 -- 即編譯器會根據傳入的參數自動地幫助我們確定T的類型:
let output = identity("myString"); // type of output will be 'string'
使用泛型變量
使用泛型創建像identity這樣的泛型函數時,編譯器要求你在函數體必須正確的使用這個通用的類型。 換句話說,你必須把這些參數當做是任意或所有類型。
看下之前identity例子:
function identity<T>(arg: T): T {
return arg;
}
如果我們想同時打印出arg的長度。 我們很可能會這樣做:
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
如果這么做,編譯器會報錯說我們使用了arg的.length屬性,但是沒有地方指明arg具有這個屬性。 記住,這些類型變量代表的是任意類型,所以使用這個函數的人可能傳入的是個數字,而數字是沒有 .length屬性的。
現在假設我們想操作T類型的數組而不直接是T。由于我們操作的是數組,所以.length屬性是應該存在的。 我們可以像創建其它數組一樣創建這個數組:
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
我們也可以這樣實現上面的例子:
function loggingIdentity<T>(arg: Array<T>): Array<T> {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
泛型類型
我們創建了identity通用函數,可以適用于不同的類型。 我們研究一下函數本身的類型,以及如何創建泛型接口。
泛型函數的類型與非泛型函數的類型沒什么不同,只是有一個類型參數在最前面,像函數聲明一樣
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <T>(arg: T) => T = identity;
我們也可以使用不同的泛型參數名,只要在數量上和使用方式上能對應上就可以。
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <U>(arg: U) => U = identity;
我們還可以使用帶有調用簽名的對象字面量來定義泛型函數:
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: {<T>(arg: T): T} = identity;
這引導我們去寫第一個泛型接口了。 我們把上面例子里的對象字面量拿出來做為一個接口:
interface GenericIdentityFn {
<T>(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn = identity;
一個相似的例子,我們可能想把泛型參數當作整個接口的一個參數。 這樣我們就能清楚的知道使用的具體是哪個泛型類型(比如: Dictionary
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
多個泛型
function fn<T, U>(a:T, b:U): T&U {
return Object.assign(a,b)
}
默認值
function find<T=number>(arr:T[],index: number):Array<T> {
return [arr[index]]
}
find([1,2, '12'], 1)
泛型約束
你應該會記得之前的一個例子,我們有時候想操作某類型的一組值,并且我們知道這組值具有什么樣的屬性。 在 loggingIdentity例子中,我們想訪問arg的length屬性,但是編譯器并不能證明每種類型都有length屬性,所以就報錯了。
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
相比于操作any所有類型,我們想要限制函數去處理任意帶有.length屬性的所有類型。 只要傳入的類型有這個屬性,我們就允許,就是說至少包含這一屬性。 為此,我們需要列出對于T的約束要求。
為此,我們定義一個接口來描述約束條件。 創建一個包含 .length屬性的接口,使用這個接口和extends關鍵字來實現約束:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
現在這個泛型函數被定義了約束,因此它不再是適用于任意類型:
loggingIdentity(3); // Error, number doesn't have a .length property
我們需要傳入符合約束類型的值,必須包含必須的屬性:
loggingIdentity({length: 10, value: 3});
斷言
我們Js是靈活的,而ts是嚴格類型的, 這導致他們可能會存在沖突。我們可以用sa斷言來解決這個沖突。
interface obj1 {
a:number,
b:number
}
let obj:obj1 = {} as obj1
// 異步請求后
obj.res = 123
function f1(a:number[]|string) {
let _a = a as Array<number>
_a.forEach(item => {console.log(item)})
}
interface fn {
(a: number): string
a: number
}
let f2:fn = function(a:number) {return 123;} as fn
f2.a = 123
// 斷言的另一種寫法,等同上面
let f2:fn = <fn>function(a:number) {return 123;}
浙公網安備 33010602011771號