
Ts進階
環境搭建
npm install typescript -g
tsc demo01.ts
node demo01.js
npm install ts-node -g
ts-node demo01.ts
靜态類型
// 靜态類型
const count: number = 1;
// count = "itxing" // 報錯
console.log(count)
interface XiaoJiejie {
username: string;
age: number;
}
const xiaohong: XiaoJiejie = {
username: "小紅",
age: 18,
}
console.log(xiaohong)
靜态類型:基礎靜态類型和對象類型
number, string, null
,
undefinde
,
symbol
,
boolean
,
void
對象類型 數組類型 類類型 函數類型
const myCount: number = 0;
const myName: string = "itxing";
const xiaoJiejie: {
name: string,
age: number,
} = {
name: "小姐姐",
age: 18
}
const xiaoJiejies: string[] = [
"小姐姐1", "小姐姐2"
]
class Person {}
const person: Person = new Person()
const jianXiaoJiejie: () => string = () => {
return "美女";
}
類型注解和類型推斷
// 類型注解 類型推斷
let a: number; // 類型注解
a = 0;
let countInference = 123; // 類型推斷
- 如果
能夠自動分析變量類型, 我們就什麼也不需要做了TS
- 如果
無法分析變量類型的話, 我們就需要使用類型注解TS
// 不用寫類型注釋
const one = 1;
const two = 2;
const three = one + two;
// 用寫類型注釋的
function getTotal(one: number, two: number) {
return one + two;
}
const total = getTotal(1, 2)
函數參數和傳回類型的注解
function getTotal(one: number, two: number): number {
return one + two;
}
const total = getTotal(1, 2);
void
function syaHello(): void {
console.log('hello world')
}
never
// never 傳回值類型 永遠執行不完
function errorFunction(): never {
throw new Error();
console.log("hello world");
}
function forNever(): never {
while (true) {}
console.log("hello world");
}
函數參數為對象(解構)時
function add({one, two}): number {
return one + two;
}
function add({ one, two }: { one: number, two: number }): number {
return one + two;
}
const total = add({one: 1, two: 2})
// 錯誤寫法
function add({one: number, two: number}): number {
return one + two;
}
function add({one}: number): number {
return one + two;
}
// 正确寫法
function add({one, two}: {one: number, two: number}): number {
return one + two;
}
數組類型注解的方法
一般數組類型定義
const numberArr:number[] = [1,2,3];
const string: string[] = ['a','b','c'];
const undefinedArr: undefined[] = [undefined];
const arr:(number | string)[] = [1, 'string', 2];
數組中對象類型的定義
const xiaojiejie: {
name: string,
age: number
}[] = [
{name: '劉英', age: 18},
{name: '謝大腳', age: 20}
]
// 别名 或 類來限制類型
type Lady = {
name: string,
age: number
}
class Madon {
name: string;
age: number
}
const xiaojiejie: Lady[] = [
{name: '劉英', age: 18},
{name: '謝大腳', age: 20}
]
元組的使用和類型限制
const xiaojiejie:(string|number)[] = ['dajiao', 'teacher', 28]
// 以下情況也不會報錯,這是有問題的
const xiaojiejie:(string|number)[] = ['dajiao', 18, 'teacher']
元組可以固定每個位置上的元素類型
const xiaojiejie: [string, string, number] = ["dajiao", "teacher", 28];
interface 接口
const screenResume = (name: string, age: number, bust: number) => {
age < 24 && bust >= 90 && console.log(name + "進入面試");
age > 24 || (bust < 90) && console.log(name + "你被淘汰了")
}
const getResume = (name: string, age: number, bust: number) => {
console.log(name + "年齡是:" + age);
console.log(name + "胸圍是:" + bust)
}
screenResume("大腳", 18, 94)
getResume("大腳", 18, 94)
接口 interface
interface Girl {
name: string;
age: number;
bust: number;
}
const girl = {
name: "大腳",
age: 18,
bust: 94,
}
const screenResume = (girl: Girl) => {
girl.age < 24 && girl.bust >= 90 && console.log(girl.name + "進入面試")
girl.age > 24 && girl.bust < 90 && console.log(girl.name + "你被淘汰")
}
const getResume = (girl: Girl) => {
console.log(girl.name + "年齡是:" + girl.age);
console.log(girl.name + "胸圍是:" + girl.bust)
}
screenResume(girl);
getResume(girl);
// 接口非必須屬性定義
// 接口非必選值定義
interface Girl {
name: string;
age: number;
bust: number;
waistline?: number;
}
// 允許加入任何值
interface Girl {
name: string;
age: number;
bust: number;
waistline?: number;
[propName: string]: any
}
接口和類的限制
interface Girl {
name: string;
age: number;
bust: number;
waistline?: number;
[propName: string]: any;
say(): string;
}
const girl = {
name: 'itxing',
age: 18,
bust: 94,
waistline: 21,
sex: '女',
say() {
return '歡迎光臨 ,天上人間大保健!!'
},
teach() {
return '我是一個老師'
}
}
const getResume = (girl: Girl) => {
console.log(girl.name + "年齡是:" + girl.age);
console.log(girl.name + "胸圍是:" + girl.bust);
girl.waistlin && console.log(girl.name + "腰圍是:" + girl.waistline);
girl.sex && console.log(girl.name + "性格是:" + girl.sex)
}
getResume(girl)
class DaMeiZi implements Girl {
name = '奶茶妹';
age = 18;
bust = 90;
say() {
return 'hello 奶茶妹'
};
}
// 如果去掉say方法就會報錯
接口繼承
interface Teacher extends Girl {
teach(): string;
}
const getResume = (girl: Teacher) => {
console.log(girl.name + "年齡是:" + girl.age);
console.log(girl.name + "胸圍是:" + girl.bust);
girl.waistlin && console.log(girl.name + "腰圍是:" + girl.waistline);
girl.sex && console.log(girl.name + "性格是:" + girl.sex)
}
getResume(girl)
// girl 對象中要追加teach方法
類的繼承
class Lady {
content = 'Hi,帥哥';
sayHello() {
return this.content;
}
}
class XiaoJieJie extends Lady {
sayLove() {
return 'I Love You';
};
// // 類的重寫
// sayHello() {
// return "Hi , honey!";
// }
sayHello() {
return super.sayHello() + '.你好'
}
}
const goddess = new XiaoJieJie();
console.log(goddess.sayHello());
console.log(goddess.sayLove())
類的重寫
class XiaoJieJie extends Lady {
sayLove() {
return 'I Love You';
};
// 類的重寫
sayHello() {
return "Hi , honey!";
}
sayHello() {
return super.sayHello() + '.你好'
}
}
super關鍵字
用于通路和調用一個對象的父對象上的函數
用法:
super([arguments]);
// 調用 父對象/父類 的構造函數
super.functionOnParent([arguments]);
// 調用 父對象/父類 上的方法
示例:
class DaMeiZi extends Lady {
sayLove() {
return 'I Lover you!'
}
sayHello() {
return super.sayHello() + '.你好'
}
}
const goddess = new DaMeiZi()
console.log(goddess.sayHello())
類的通路類型private protected public
class Person {
name: string;
}
const person = new Person();
person.name = 'itxing';
console.log('================', person.name);
預設對name的通路屬性進行了定義public
public:允許在類的内部和外部被調用
class Person {
public name: string;
public sayHello() {
console.log(this.name + ' say Hello')
}
}
const person = new Person();
person.name = 'itxing';
person.sayHello();
console.log(person.name);
private: 隻允許在類的内部被調用,外部不允許調用
class Person {
private name: string = 'itxing';
public sayHello() {
// 類内部通路
console.log(this.name + ' say Hello')
}
}
// 類外部通路報錯
const person = new Person()
person.name = 'itxing'; // 報錯
person.sayHello(); // 輸出 itxing say hello
console.log(person.name); // 報錯
允許在類中及繼承的子類中使用
class Person {
protected name: string = 'itxing';
public sayHello() {
console.log(this.name + ' say Hello')
}
}
const person = new Person();
person.name = '頁面仔'; // 報錯
class Teacher extends Person {
public sayBye() {
console.log(this.name + ' say Bye')
}
}
const teacher = new Teacher();
teacher.sayBye(); // 正常
類的構造函數
希望在new出對象的時候,直接通過傳遞參數的形式
class Person {
public name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person('itxing');
console.log(person.name);
// 簡寫
class Person {
constructor(public name: string) {}
}
類繼承中的構造器寫法
class Person {
constructor(public name: string) {}
}
class Teacher extends Person {
constructor(public age: number, name: string) {
super(name);
}
}
const teacher = new Teacher(18, 'itxing');
console.log(teacher.age);
console.log(teacher.name);
類中可以不寫構造函數(預設執行構造函數),子類繼承父類時有構造函數時必須執行super(),需要傳值進行傳值操作
class Person {}
class Teacher extends Person {
constructor(public age: number) {
super()
}
}
const teacher = new Teacher(20);
teacher.age;
類的Getter、Setter
getter屬性的關鍵字:get,擷取某屬性的值,它不是一個方法,歸根到底還是屬性
setter屬性的關鍵字:get,改變某屬性的值
getter
class Person {
constructor(private _age: number) {}
get age() {
return this._age - 10;
}
}
const person = new Person(28);
console.log(person.age);
setter
class Person {
constructor(private _age: number) {}
get age() {
return this._age - 10
}
set age(age: number) {
this._age = age;
}
}
const person = new Person(28);
console.log(person.age);
person.age = 25;
console.log(person.age);
類的static
正常寫法
class Girl {
sayLove() {
return "I Love you";
}
}
const girl = new Girl();
console.log(girl.sayLove());
static
class Girl {
static sayLove() {
return 'I love you';
}
}
console.log(Girl.sayLove());
類的隻讀屬性
class Person {
constructor(public name: string) {}
}
const person = new Person('itxing')
console.log(person.name)
若name隻能讀,則用readonly
class Person {
public readonly _name: string;
constructor(name: string) {
this._name = name;
}
}
const person = new Person('itxing');
person._name = '頁面仔'; // 報錯
console.log(person._name)
抽象類
BaseTeacher、MiddleTeacher、SeniorTeacher類被抽象類Person限制,必須有skill方法
abstract class Person {
abstract skill() // 因為沒有具體方法,是以不寫大括号
}
class BaseTeacher extends Person {
skill() {
console.log('普通老師');
}
}
class MiddleTeacher extends Person {
skill() {
console.log('中級老師');
}
}
class SeniorTeacher extends Person {
skill() {
console.log('進階老師');
}
}
聯合類型和類型保護
所謂聯合類型:一個變量可能有兩種或兩種以上的類型
interface BaseTeacher {
teach: boolean;
say: () => {};
}
interface MiddleTeacher {
teach: boolean;
skill: () => {}
}
function judgeWho(teacher: BaseTeacher | MiddleTeacher) {
teacher.say(); // 報錯
}
類型保護-類型斷言
// 根據teach值,通過斷言方式進行類型保護
function judgeWho(teacher: BaseTeacher | MiddleTeacher) {
if (teacher.teach) {
(teacher as MiddleTeacher).skill();
} else {
(teacher as BaseTeacher).say();
}
}
類型保護-in文法
function judgeWho(teacher: BaseTeacher | MiddleTeacher) {
if ('skill' in teacher) {
teacher.skill();
} else {
teacher .say();
}
}
類型保護-typeof文法
function add(first: string | number, second: string | number) {
if (typeof first === 'string' || typeof second === 'string') {
return `${first}${second}`
}
return first + second;
}
類型保護-instanceof文法
function addObj(first: object | NumberObj, second: object | NumberObj) {
if (first instanceof NumberObj && second instanceof NumberObj) {
return first.count + second.count;
}
return 0;
}
Enum枚舉類型
enum Status {
Base,
Middle,
Senior
}
function getLearn(level: any) {
if (level === Status.Base) {
return 'base';
} else if (level === Status.Middle) {
return 'middle'
} else if (level === Status.Senior) {
return 'senior'
}
}
console.log(getLearn(1)) // 輸出 middle
enum預設0 1 2,如果想從1開始
enum Status {
Base = 1,
Middle,
Senior
}
泛型
function join(first: string | number, second: string | number) {
return `${first}${second}`
}
console.log(join(頁面仔', '小楊'))
如果希望first和second的資料類型相同,我們就可以使用泛型
function join<T>(first: T, second: T) {
return `${first}${second}`
}
console.log(join<string>('頁面仔', '小楊'))
泛型中數組的使用
function myFun<T>(params: T[]) {
return params;
}
console.log('============', myFun<string>(['123', '456']))
或
function myFun<T>(params: Array<T>) {
return params;
}
多個泛型的定義
function join<T, P>(first: T, second: P) {
return `${first}${second}`
}
console.log(join<string, number>('1', 2))
泛型類型推斷(不推薦)
console.log(join('1', 2))
初始類的泛型
class SelectTeacher<T> {
constructor(private teachers: T[]) {}
getTeacher(index: number): T {
return this.teachers[index];
}
}
const selectTeacher = new SelectTeacher(['初級老師', '中級老師', '進階老師']);
console.log('==================', selectTeacher.getTeacher(1))
泛型中的繼承
interface Teacher {
name: string;
}
class SelectTeacher<T extends Teacher> {
constructor(private teachers: T[]) {}
getTeacher(index: number): string {
return this.teachers[index].name
}
}
const selectTeacher = new SelectTeacher([
{ name: '初級老師' },
{ name: '中級老師' },
{ name: '進階老師' }
])
console.log('===============', selectTeacher.getTeacher(1))
泛型限制
泛型可以是任意類型,但現在要求泛型是string或number
class SelectTeacher<T extends number | string> {
// ......
}
命名空間Namespace
mkdir ts-web
cd ts-web
npm init -y
tsc -init
mkdir src dist
touch index.html
cd src
touch page.ts
// 配置 tsconfig.json "outDir": "./dist", "rootDir": "./src"
檢視相關代碼
// page.ts
console.log('hello itxing')
index.html中引入page.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./dist/page.js"></script>
</head>
<body>te-web</body>
</html>
終端執行指令并打開頁面
tsc
沒有命名空間的問題
// page.ts
class Header {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Header'
document.body.appendChild(elem)
}
}
class Content {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Content'
document.body.appendChild(elem)
}
}
class Footer {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Footer'
document.body.appendChild(elem)
}
}
class Page {
constructor() {
new Header();
new Content();
new Footer();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./dist/page.js"></script>
</head>
<body>
te-web
<script> new Page() </script>
</body>
</html>
通過檢視
./build/page.js
檔案可以看出全部都是
var
聲明的變量,過多的全局變量會讓我們代碼變的不可維護。
命名空間的使用
namespace Home {
class Header {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Header'
document.body.appendChild(elem)
}
}
class Content {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Content'
document.body.appendChild(elem)
}
}
class Footer {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Footer'
document.body.appendChild(elem)
}
}
export class Page {
constructor() {
new Header();
new Content();
new Footer();
}
}
}
new Home.Page()
命名空間實作元件化
cd src
touch components.ts
namespace Components {
export class Header {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Header'
document.body.appendChild(elem)
}
}
export class Content {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Content'
document.body.appendChild(elem)
}
}
export class Footer {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Footer'
document.body.appendChild(elem)
}
}
}
page.ts
namespace Home {
export class Page {
constructor() {
new Components.Header();
new Components.Content();
new Components.Footer();
}
}
}
index.html
<script src="./dist/components.js"></script>
<script src="./dist/page.js"></script>
多檔案編譯成一個檔案
tsconfig.json
"module": "amd",
"outFile": "./dist/page.js"
這樣會編譯成一個檔案,index.html中隻需引入page.js即可