本系列是博主在學習 TS 過程當中 閱讀以下文檔作出的筆記 若是有錯誤 但願在評論區指出哦 🤩🤩🤩javascript
TypeScript 入門教程html
深刻理解 TypeScriptjava
TypeScript 官網python
babelreact
預計將會更新以下內容git
TS 小冊 - 類型系統 ✅ ✅github
TS 小冊 - 高級類型typescript
TS 小冊 - 模塊shell
TS 小冊 - 工具函數
TS 小冊 - JSX 和 React
...... (TODO) 好吧 我也不知道 最後會是怎樣 😛😛😛
本文涉及的代碼 github.com/LuckyChou71…
// boolean
let isDone: boolean;
// number
let count: number;
// string
let username: string;
// symbol
let unique: symbol;
// bigint
let bigBigBigNum: bigint;
/** * 默認狀況下null和undefined是全部類型的子類型 * 就是說你能夠把null和undefined賦值給number類型的變量 * 指定了--strictNullChecks標記,null和undefined只能賦值給void和它們各自 */
// undefined
let u: undefined;
// null
let n: null;
/** * never類型是任何類型的子類型,也能夠賦值給任何類型 * 然而,沒有類型是never的子類型或能夠賦值給never類型(除了never自己以外) * 即便any也不能夠賦值給never */
function error(message: string): never {
throw new Error(message);
}
複製代碼
// 數組
let arr1: number[];
// 數組泛型
let arr2: Array<number>;
// 元組 能夠限制元素的類型和個數
let arr3: [number, string];
// 最使人熟知的可能就是React的useState 它返回了一個元組
const [state, useState] = React.useState(null);
複製代碼
// 爲函數定義類型
// 不能使用interface 由於interface只能定義對象
type Add = (x: number, y: number) => number;
function add1(x: number, y: number): number {
return x + y;
}
const add2: Add = (x: number, y: number): number => {
return x + y;
};
// 剩餘參數
function add3(x: number, ...y: Array<number>) {
return x + y.reduce((x, y) => x + y);
}
// 默認參數
// 若是你想要默認參數生效的話 就把默認參數放在參數序列的最後一項吧
// 以下定義 就會形成歧義 編譯器不知道傳入一個參數的時候 到底想表達的是哪個值
// 最終 咱們若是想避免程序報錯的話 就不得不乖乖的傳入第二個參數 這樣咱們的默認參數就失效了
function add4(x: number = 2, y: number) {
return x + y;
}
add4(3, 5);
// 可選參數
// 可選參數必須放在參數序列的最後一項
function add5(x: number, y?: number) {
return x + y;
}
// 函數重載
function showType(x: any): any {
if (typeof x === 'number') {
return 'number';
} else if (typeof x === 'string') {
return 'string';
} else {
return "I don't know";
}
}
複製代碼
/** * 默認狀況下,從0開始爲元素編號 * 也能夠手動爲某個枚舉值賦值 下一個枚舉值爲前一個枚舉值 + 1 */
enum Color {
Red,
Green,
Blue,
}
Color.Blue; // -->2
enum Count {
one = 1,
two,
three,
}
Count.three; // --> 3
// 減小魔法數字
enum STATUS {
READY = 0,
OK = 1
FAILED = -1
}
// 字符串枚舉
enum Lang {
js = 'javascript',
ts = 'typescript',
jsx = 'react',
py = 'python',
}
複製代碼
若是你感興趣它是如何實現的話 你能夠在 babel 官網去轉換它們
大體它們被 babel 轉換成以下
'use strict';
var Color;
(function (Color) {
Color[(Color['Red'] = 0)] = 'Red';
Color[(Color['Green'] = 1)] = 'Green';
Color[(Color['Blue'] = 2)] = 'Blue';
})(Color || (Color = {}));
var Count;
(function (Count) {
Count[(Count['one'] = 1)] = 'one';
Count[(Count['two'] = 2)] = 'two';
Count[(Count['three'] = 3)] = 'three';
})(Count || (Count = {}));
var Lang;
(function (Lang) {
Lang['js'] = 'javascript';
Lang['ts'] = 'typescript';
Lang['jsx'] = 'react';
Lang['py'] = 'python';
})(Lang || (Lang = {}));
複製代碼
// 類繼承接口
interface IPerson {
readonly name: string;
}
// Person類中須要定義全部IPerson接口中的成員
class Person implements IPerson {
// 公開 和不加修飾符 效果同樣 表示在任意位置均可以訪問
public nickname: string;
// 只讀 只能讀取 不能賦值
readonly name: string = '花匠';
// 受保護的 protected成員在派生類中仍然能夠訪問
protected gender: string;
// 私有 不能在聲明它的類的外部訪問
private _age: number;
constructor(nickname: string, gender: string, age: number) {
this.nickname = nickname;
this.gender = gender;
this._age = age;
}
// 靜態方法 使用類型.調用
static sayHi() {
console.log(this.name);
}
// getters/setters 存取器件
set age(age: number) {
this._age = age;
}
get age(): number {
return this._age;
}
}
const person = new Person('nanshu', 'man', 18);
person.name; // --> 花匠
person.nickname; // --> nanshu
// 不能訪問gender 由於gender是protected 只能在聲明的類和派生類中訪問
// person.gender; Property 'gender' is protected and only accessible within class 'Person' and its subclasses.
// 不能訪問gender 由於age是private 只能在聲明的類中訪問
// stu.age; Property 'age' is private and only accessible within class 'Student'
class Student extends Person {
constructor(nickname: string, gender: string, age: number) {
super(nickname, gender, age);
// 不能訪問父類中的私有成員
// super.age; Property 'age' is private and only accessible within class 'Person'.
// public protected readonly修飾的成員均可以訪問
super.name;
super.nickname;
super.gender;
}
}
// 和接口不一樣 接口不能包含成員的實現細節 且不能包含修飾符
// 可是抽象類能夠包含成員的實現細節 而且能夠包含訪問修飾符
abstract class Animal {
constructor(public name: string) {
this.name = name;
}
abstract makeSound(): void;
move(): void {
console.log('moving...');
}
}
class Dog extends Animal {
makeSound() {
console.log('make sound');
}
}
const dog = new Dog('小花');
dog.name; // --> 小花
dog.move(); // --> moving
dog.move(); // --> make sound
// 類看成接口使用
class Point {
x: number;
y: number;
}
const pointA: Point = { x: 7, y: 10 };
interface Point3D extends Point {
z: number;
}
const pointB: Point3D = { x: 7, y: 1, z: 10 };
複製代碼
// 泛型函數
// 若是咱們想實現一個函數 相似shell中的echo 輸入什麼就返回什麼
// 可是 咱們不知道用戶在實際使用的時候 會傳入什麼類型 固然咱們可使用any 可是這🧐好像很隨意
// 或者咱們可使用函數重載 爲每個類型具體定義 這好像又🤨
// 這個時候咱們就可使用泛型
function echo<T>(arg: T): T {
return arg;
}
// 泛型類
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
// 泛型約束
// 由於編譯器不知道泛型 T 中擁有哪些方法 因此以下調用會會被ts警告⚠️
function loggingIdentity1<T>(arg: T): T {
// console.log(arg.length); Property 'length' does not exist on type 'T'.
return arg;
}
// 咱們能夠定義一個接口 讓泛型繼承這個接口 這樣咱們就能夠安全的使用lenght屬性了
interface Lengthwise {
length: number;
}
function loggingIdentity2<T extends Lengthwise>(arg: T): T {
// 這個時候就不會被ts警告⚠️了
console.log(arg.length);
return arg;
}
複製代碼
/** * 沒法聲明基本數據類型 只能聲明對象 * 最簡單判斷該用readonly仍是const的方法是看要把它作爲變量使用仍是作爲一個屬性。 * 作爲變量使用的話用const,若作爲屬性則使用readonly */
interface IPerson {
name: string;
height?: number;
readonly age: number;
}
// 多個interface會合並
interface IPerson {
weight: number;
}
const person: IPerson = {
name: 'nanshu',
height: 181,
weight: 140,
age: 18,
};
// 索引簽名
// 表示這個對象接受 任意string的鍵 any的值
interface LooseObj {
[k: string]: any;
}
// 你也能夠設置這個索引簽名爲只讀
interface ReadOnlyLooseObj {
readonly [k: string]: any;
}
interface LooseArr {
[k: number]: any;
}
const arr: LooseArr = [1, '1', true];
複製代碼
// 類型別名用來給類型起一個新的名字
// 起別名不會新建一個類型 --> 它建立了一個新名字來引用那個類型
type Name = string;
type NameResolver = () => string;
const nickname: Name = 'nanshu';
const handleNameResolver: NameResolver = () => 'nanshu';
// 不一樣與interface type不能重複命名 可是type能夠聲明基本數據類型
// type Name = number; Duplicate identifier 'Name'.
複製代碼