【尚硅谷TypeScript教程(李立超老师TS新课)】
TypeScript演练场
npm
全局安装typescript
npm i -g typescript
ts
文件tsc
对ts
文件进行编译
tsc 文件名.ts
类型声明
TS
非常重要的一个特点TS
中的变量(参数、形参)的类型TS编译器
会自动检查是否符合类型声明,符合则赋值,否则报错let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数:类型, 参数:类型): 类型{
...
}
自定类型判断
TS
拥有自动的类型判断机制同时进行
的,TS编译器
会自动判断变量的类型类型
类型 | 例子 | 描述 |
---|---|---|
number | 1, -33, 2.5 | 任意数字 |
string | ‘hi’, “hi” | 任意字符串 |
boolean | true、false | 布尔值true 或 false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空(undefined) | 没有值(或 undefined) |
never | 没有值 | 不能是任何值 |
object | {name:‘孙悟空’} | 任意的JS对象 |
array | [1,2,3] | 任意JS数组 |
tuple | [4,5] | 元素,TS新增类型,固定长度数组 |
enum | enum{A,B} | 枚举,TS中新增类型 |
number
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;
boolean
let isDone: boolean = false;
string
let color: string = "blue";
color = 'red';
let fullName: string = `Bob Bobington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.
I ll be ${age +1} years old next month.`
字面量
也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
let color: 'red' | 'blue' | 'black';
let num: 1 | 2 | 3 | 4 | 5;
any
let d: any = 4;
d = 'hello';
d == true;
unknown
let notSure: unknown = 4;
notSure = 'hello';
void
let unsable: void = undefined;
never
function error(message: string): never {
throw new Error(message);
}
object(没啥用)
let obj: object = {};
array
let list: number[] = [1,2,3];
let list: Array<number> = [1,2,3];
tuple
let x: [string, number];
x = ["hello",10];
enum
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
enum Color {
Red = 1,
Green = 2,
Blue = 4
}
let c: Color = Color.Green;
类型断言
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
-w
指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。tsc xxx.ts -w
tsc
指令,则可以自动将当前项目下的所有ts文件编译为js文件。tsc
指令的前提是,要先在项目目录下创建一个ts的配置文件tsconfig.json
tsconfig.json
是一个JSON文件,添加配置文件后(添加配置文件命令,在VSCode终端中输入tsc -init
),只需要tsc
指令即可完成对整个项目的编译。[**/*]
"include":["src/**/*","tests/**/*"]
上述例子中,所有src目录和tests目录下的文件都会被编译["node_modules","bower_components","jspm_packages"]
"exclude": ["./src/hello/**/*"]
上述示例中,src和hello目录下的文件都不会被编译"extends": "./configs/base"
"files": [
"core.ts",
"sys.ts",
"types.ts"
]
列表中的文件都会被TS编译器所编译 {
"compilerOptions": {
"target": "ES6",
"module": "system",
"outDir": "./dist",
// "outFile": "./dist/app.js",
"allowJs": false,
"checkJs": false,
"removeComments": false,
"noEmit": false,
"noEmitOnError": true,
"strict": true,
"alwaysStrict": true,
"noImplicitAny": false,
"noImplicitThis": true,
"strictNullChecks": true
}
}
'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node16', 'nodenext'.
可选项:‘es5’, ‘es6’, ‘es2015’, ‘es7’, ‘es2016’, ‘es2017’, ‘es2018’, ‘es2019’, ‘es2020’, ‘es2021’, ‘esnext’, ‘dom’, ‘dom.iterable’, ‘webworker’, ‘webworker.importscripts’, ‘webworker.iterable’, ‘scripthost’, ‘es2015.core’, ‘es2015.collection’, ‘es2015.generator’, ‘es2015.iterable’, ‘es2015.promise’, ‘es2015.proxy’, ‘es2015.reflect’, ‘es2015.symbol’…
"outDir": "./dist"
outFile
后,所有的全局作用域合并在一个文件中,module
中只有’amd’
和 ‘system’
支持outFile
。"outFile": "./dist/app.js"
"allowJs": false
"checkJs": false
"removeComments": true
"noEmit": true
"noEmitOnError": false
"strict": true
"alwaysStrict": true
"noImplicitAny": true
"noImplicitThis": true
"strictNullChecks": true
用关键字class
来声明一个类
class Person{
...
}
在TS中类的属性一共有三种,在属性面前添加相应的修饰符便可
class Person{
name:string = "zhubajie" // 实例属性
static age = 89 // 类属性
readonly addr:string = "高老庄" // 只读属性
}
static
开头的属性为类属性Person.age
readonly
定义的属性为只读属性,不可修改readonly
也可以放再static
后面pubilc
公共属性,可以再任意位置访问和修改(实例属性,实例化之后访问)
private
私有属性,只能在类的内部进行访问和修改(一般声明的时候我们会以_开头)
protected
受保护的属性,只能在当前类和当前类的子类中进行访问
class Person{
public name = "SunWuKong"
private age = 30
protected sex = "male"
}
const person = new Person()
console.log(person.name)
console.log(person.age) // 错误 只能在Person这个类中进行访问
console.log(person.sex) // 错误 只能在Person这个类和其子类中访问
此外,还有readOnly
属性,以他修饰的属性只能读取不能修改
getter
方法和setter
方法getter
方法用于获取属性setter
方法用于设置属性class Person1{
private _name:string
constructor(name:string){
this._name = name;
}
set name(value:string){
this._name = value
}
get name(){
return this._name
}
}
当我们进行读取的时候,其实是走的get这个逻辑经过static
关键字修饰的方法属于类方法,可以通过类直接使用
class BaJie{
name = "BaJie"
static age = 18
static sayName(){
console.log("八戒")
}
}
// 通过类直接访问
BaJie.sayName()
console.log(BaJie.age);
const bajie = new BaJie()
bajie.sayName() // 实例化之后不可访问
当有不规范的语法的时候,ts就不会进行编译,如上面的编译如下
var BaJie = /** @class */ (function () {
function BaJie() {
this.name = "BaJie";
}
BaJie.sayName = function () {
console.log("八戒");
};
BaJie.age = 18;
return BaJie;
}());
// 通过类直接访问
BaJie.sayName();
console.log(BaJie.age);
在类中直接定义的方法为实例方法,没有任何关键字的修饰
这种方法只能在类实例化之后进行使用
class BaJie{
name = "BaJie"
age = 18
sayName(){
console.log("八戒")
}
}
// 通过类直接访问
BaJie.sayName() // 错误的访问方法
console.log(BaJie.age); // 错误的访问方法
// 同样,实例化之后也是可以访问的
const bajie = new BaJie()
bajie.sayName()
console.log(bajie.name);
class Person{
name:string;
age:nubmer;
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
const p1 = new Person('张三',18);
const p2 = new Person('李四',20);
console.log(p1);
console.log(p2);
constructor
被称为构造函数
构造函数会在对象创建时调用
// 父类
class Animal{
name:string;
age: number;
constructor(name:string,age:number){
this.name = name;
this.age = age
}
sayName(){
console.log(this.name)
}
}
// 子类
class Dog extends Animal{
run(){
console.log(`${this.name}run`);
}
}
class Cat extends Animal{
sayName(){
console.log(`我是${this.name}`);
}
}
const dog = new Dog("旺财",19)
const cat = new Cat("汤姆",20)
dog.sayName()
dog.run()
cat.sayName()
可以将代码复制到 TypeScript演练场 运行
我们使用extends
关键字来进行继承
,其中被继承的Animal
为父类,Dog
为子类
继承之后,子类会拥有父类的一切属性和方法
子类也可以自己定义一些方法,如上面例子中的run
子类也可以写与父类相同的方法,这样执行方法的时候会执行子类的方法,叫做方法重写
(Cat
类中重写了sayName
方法)
abstract class Animal{
name:string;
constructor(name:string){
this.name = name;
}
abstract sayName():void;
}
class Dog extends Animal{
age:number;
constructor(name:string,age:number){
super(name);
this.age = age;
}
sayName(): void {
console.log(`我是${this.name},我今年${this.age}岁了`);
}
}
const dog = new Dog("旺财",23)
dog.sayName() // 我是旺财,我今年23岁了
用abstract
关键字来定义抽象类和抽象方法
不能用来创建对象
只能用于继承
(说明类中有哪些属性,哪些方法)抽象方法没有方法体
(如sayName方法),且只能定义在抽象类中必须对于抽象类中的抽象方法进行复写
接口用于描述一个类或者一个对象的结构,描述他们的属性和方法,所以接口可以当做一个类的声明
我们使用interface
来定义一个接口,定义的方法全部为抽象方法
,必须重写
接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
同时接口也可以当成类型声明去使用
interface myInterface{
name:string,
age:number,
sex:"male"|"female",
sayName():void
}
一般我们使用implements
关键字来使用接口
class Person implements myInterface{
name: string;
age: number;
sex: "male" | "female";
sayName(): void {
console.log(this.name);
}
}
使用extends
来进行接口的继承,且后可以跟多个接口
,实现多重继承
interface Obj {
[propName:string]:any
}
interface myInterface{
name:string,
age:number
}
interface IPerson extends myInterface,Obj{
sex:"male"|"female",
sayName():void
}
class Person implements IPerson{
name: string;
age: number;
sex: "male" | "female";
hobby:"read"|"write"
sayName(): void {
console.log(this.name);
}
}
在指定函数或者类的时候,如果遇到类型不明确的话,就可以使用泛型
(不先指定类型,使用的时候进行类型的转换)
一般在声明的变量后面加一个尖括号来声明泛型
当我们进行类型转换后,编辑器就会有相应的提示
当然我们也可以不指定泛型,ts会进行自动的类型转换
function fn1<T,K>(a:T,b:K):K{
console.log(a);
return b
}
fn1<number,string>(1,'hello')
class Person3<T>{
name:T
constructor(name:T){
this.name = name
}
}
const person4 = new Person3<string>("Jack")
console.log(person.name);
extends
关键字,他表示泛型必须满足接口的条件interface IPerson1{
name:string,
age:number
}
function fn2<T extends NameInterface>(a:T):string{
return a.name
}
fn2<IPerson1>({name:"小敏",age:10})