类型声明
变量类型声明
参数类型声明
返回值类型声明
声明变量时要指定类型。如:let a: number;
声明变量指定类型并初始化值。如:let a: number = 10;
声明变量自动进行类型检测。如:let a = true;
传参声明类型、返回值声明类型
// 指定参数number类型 指定返回值number类型
function sum(a: number, b: number): number{
return a + b;
}
基本类型
image.png- 字面量
// b只能是二者其一
let b: "male" | "female";
b = "male";
b = "female";
- any 与 unknown
任意类型,一个变量设置类型为any后相当于对该变量关闭了ts对类型的检测
// 显示any
let a: any;
a = 1;
a = "hello";
// 隐式any
let d;
d = 10;
d = true;
d = 'hello';
// 未知类型
let b: unknown;
b = 10;
b = true;
let c: string;
c = d;// 编译通过,此时 c的类型不再是string, 而是any
c = b;// 编译不通过,类型一致
// 类型断言 2种语法
c = d as string;
c = <string> d;
unknown 是一个类型安全的any类型,不能直接赋值给其他类型的变量。一定要赋值需要做类型判断。
any 与 unknown的区别,any类型的变量赋值给其他类型的变量,会改变该变量的类型为any类型。
类型断言,用来告诉解析器变量的实际类型
- void 与 never
// 返回值为空的函数
function fn(): void{
return null;// 可以 return null 和 undefined
}
// 没有返回值的函数
function fn2(): never{
throw new Error("error");
}
- object
// 声明对象,有name属性类型是string的对象
// ? 可选属性
let a = {name: string, age?: number};
a = {name: 'A'};
// 普通对象
// 可选属性
let c: {name: string,age?: number} = {name: 'jack'}
// 任意类型的属性
let b: {name: string,[key: string]: any};
b = {name: 'jack', age: 18, gender: 'male'}
// 函数对象
// 声明函数类型的变量 d
let d: (a: number, b: string)=>void;
d = function(a: number, b: string): void {
console.log(a, b)
}
- array
// 字符数组
let e: string[] = ['jack', 'rose'];
// number数组 方式一
let f: number[] = [1, 2, 3];
f = [1, 2, 3, 4, 5];
// number数组类型 方式二
let g: Array<number> = [1, 2, 3];
- 元组
元组是固定长度的数组
// 元组 长度固定的数组
let h: [string,string] = ['jack', 'rose'];
- 枚举
// 定义枚举类
enum Color {
Red,
Green,
Blue
}
let i: Color = Color.Red;
if(i === Color.Red){
console.log('red')
}else if(i === Color.Green){
console.log('green')
}else if(i === Color.Blue){
console.log('blue')
}
let j: {name:string, color: Color} = {name: 'jack', color: Color.Red}
- 联合类型(
|
) 与 类型别名(type
)
// 联合类型 满足其中一种类型即可
let k: string | number = 'jack';
// 须同时满足多个
let l: {name: string} & {age: number} = {name: 'jack', age: 18};
// 类型别名
type myType = string | number | boolean;
let m: myType = 'jack';
编译配置
tsconfig.json
{
/*
include: 用来指定哪些ts文件需要被编译
** 表示任意目录
* 表示任意文件
*/
"include": [
"src/**/*"
],
// 用来指定哪些ts文件不需要被编译
"exclude": [
"node_modules",
"dist"
],
// 用来指定继承其他tsconfig.json文件
"extends": "./tsconfig.base.json",
// 用来指定哪些ts文件需要被编译
"files": [
"src/index.ts"
],
"compilerOptions": {
// 编译为es的版本
"target": "es5",
// 指定模块化规范
"module": "ES6",
// 指定项目中使用的库
"lib": [
"DOM",
"ES2015"
],
// 编译后的文件存放目录
"outDir": "./dist",
// 所有的全局作用域中的代码会合并到同一个文件中
"outFile": "./dist/index.js",
// 是否允许编译js文件
"allowJs": false,
// 是否检查js代码是否符合语法规范
"checkJs": false,
// 是否移除注释
"removeComments": false,
// 不生成编译后的文件
"noEmit": false,
// 当有错误时不生成编译文件
"noEmitOnError": false,
// 设置编译后的文件是否使用严格模式
"alwaysStrict": false,
// 不允许出现隐式的any类型
"noImplicitAny": false,
// 不允许出现不明确类型的this
"noImplicitThis": false,
// 严格检查null值
"strictNullChecks": false,
// 所有严格检查的总开关
"strict": false,
}
}
继承
构造函数、this、重写方法、super
// 定义一个类
class Person {
// 声明,构造函数中赋值
weight: number;
// 构造函数----对象创建时调用
constructor(wieght: number) {
// 构造函数中的 this 指向当前创建的实例对象
// 可以通过 this 添加属性和方法
this.weight = wieght;
}
// 实例属性
name: string = "蓝色";
// 静态属性
static age: number = 18;
// 只读属性
readonly height: number = 180;
// 实例方法
sayHi() {
console.log(`你好,我是 ${this.name},我今年 ${Person.age} 岁`);
}
// 静态方法
static sayHi() {
console.log(`你好,我是 ${Person.age} 岁的 ${Person.name}`);
}
}
const per = new Person(60);
// 访问实例属性
console.log(per.name);
// 访问静态属性
console.log(Person.age);
// 修改实例属性
per.name = "红色";
Person.age = 20;
// 调用实例方法
per.sayHi();
Person.sayHi();
// extends 继承
// 子类拥有父类所有的属性和方法
class Student extends Person {
// 子类自有方法 也是一种扩展 遵循开闭原则(OCP,open close principle)
start() {
console.log("开始学习");
}
// 重写父类的方法,会覆盖父类的sayHi方法
sayHi() {
console.log("你好,我是学生");
}
}
// 子类Teacher
class Teacher extends Person {
salary: number;
constructor(weight: number) {
// 调用父类的构造函数
super(weight);
// 初始化子类的属性
this.salary = 10000;
}
teach() {
console.log("开始教学");
}
// 重写
sayHi() {
// 调用父类的 sayHi 方法
super.sayHi();
console.log("你好,我是老师");
}
}
const stu = new Student(20);
stu.sayHi();// 你好,我是学生
const tea = new Teacher(20);
tea.sayHi();// 你好,我是老师
// 构造函数简写形式
class Animal{
// 语法糖 自动赋值
constructor(public name: string, public age: number){
}
}
抽象类
关键字:abstract
抽象类不能用来被创建对象,可以声明抽象方法
// 抽象类
abstract class Animal{
// 抽象方法 只定义结构 子类必须重写抽象方法
abstract sayHi(): void;
// 定义普通方法
sayHello(){
console.log("我是猫");
}
}
class Cat extends Animal{
// 重写抽象方法
sayHi(){
console.log("我是猫");
}
}
const cat = new Cat();
// 调用普通方法
cat.sayHello();
// 调用子类重写的方法
cat.sayHi();
接口
定义接口:interface
实现接口:implements
接口之间可以继承,交叉
// 接口 定义一个类的结构
interface IPerson{
name: string;
age: number;
sayHi(): void;
}
// 可以定义多个同名的接口,
interface IPerson{
gender: string;
}
// IPerson接口类型的对象
const person: IPerson = {
name: "张三",
age: 18,
sayHi() {
console.log("我是张三");
},
gender: "男"
}
// implements 实现接口
class Persons implements IPerson{
name: string;
age: number;
sayHi(): void {
throw new Error("Method not implemented.");
}
gender: string;
constructor(name: string, age: number, gender: string){
this.name = name;
this.age = age;
this.gender = gender;
}
}
接口继承
interface Point2D{
x: number;
y: number;
}
// 接口继承
interface Point3D extends Point2D {
z: number;
}
// 实现类
class Point implements Point3D {
z: number;
x: number;
y: number;
constructor(x: number, y: number, z: number) {
this.x = x;
this.y = y;
this.z = z;
}
}
交叉类型
符合:&
功能类似于接口继承,用于组合多个类型为一个类型。
交叉类型与接口继承的区别是在实现类型组合时,处理同名属性冲突的方式不同
interface Person{
name: string;
}
interface Contact{
phone: string;
}
// 交叉类型 给交叉类型定义一个别名
type PersonDetail = Person & Contact;
let obj: PersonDetail = {
name: 'John',
phone: '15300000000'
}
// 同时实现多个接口
class MyPerson implements Person , Contact{
name: string;
phone: string;
constructor(name: string, phone: string){
this.name = name;
this.phone = phone;
}
}
// 实现交叉类型的接口
class My implements PersonDetail{
name: string;
phone: string;
constructor(name: string, phone: string){
this.name = name;
this.phone = phone;
}
}
// 处理同名属性的不同方式
interface A{
fn:(value:number)=>string;
}
interface B {
fn:(value:string)=>string;
}
// 交叉类型
type C = A & B;
let c:C = {
fn:(value:string | number)=>'string'
}
// 接口继承同名属性接口会报错
interface B extends A{
fn:(value:string)=>string;// 因属性名与A接口的属性名相同,所以无法进行继承,会报错
}
image.png
索引前面类型 [key: string]
interface AnyObject {
// 只要是属性名是字符串都可以出现在对象中
// 约束属性名只能是字符串,值是number类型
[key: string]: number;
}
let obj: AnyObject = {
a: 1,
b: 2,
c: 3,
}
- 使用
[key: string]
来约束改接口中运行出现的属性名称。表示只要是string类型的属性名称都可出现在对象中。 - key只是一个占位符
映射类型 [key in type]
| [key in keyof]
基于旧类型创建新类型。
// 联合类型 旧类型
type PropKeys = 'x' | 'y' | 'z';
let a: PropKeys = 'x';
// 正常写法
type Type1 = {x: number, y: number, z: number};
// 映射类型 key 必须是 PropKeys类型中的 x , y , z
type Type2 = {[key in PropKeys]: number};
// 类型类型的映射
// 旧对象类型
type Props = {a: number, b: string, c: boolean}
// 新对象类型
type Type3 = {[key in keyof Props]: Props[key]};
let t3: Type3 = {
a: 1,
b: '2',
c: true
}
封装
class Parent{
// public 公共属性 在类的内部和外部访问属性和方法
// private 私有属性 将属性和方法限制为只能在类的内部访问
// protected 保护属性 在类的内部和子类中可以被访问
private _name: string;
private _age: number;
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
// 通过方法 读取 修改属性
getName() {
return this._name;
}
setName(name: string) {
this._name = name;
}
getAge() {
return this._age;
}
setAge(age: number) {
if(age < 0) return;
this._age = age;
}
// ts中设置 getter | setter 方法的方式
get name(){
return this._name;
}
get age(){
return this._age;
}
set name(name: string){
this._name = name;
}
set age(age: number){
if(age < 0) return;
this._age = age;
}
}
const par = new Parent('张三', 18);
// 修改私有属性
par.setName('李四');
// 读取私有属性
const age = par.getAge;
// 修改
par.age = 20;
const ages = par.age;
泛型
function fn<T> (param: T): T{
console.log(param);
return param;
}
// 函数调用
// 不指定泛型,TS可以自动推断出类型
fn(10);
// 指定泛型
fn<string>('name');
// 指定多个泛型
function fn2<T, U> (param: T, param2: U): T{
console.log(param);
return param;
}
fn2(1,'a');
fn2<string, number>('a', 1);
// 指定接口作为泛型
interface Inter{
name: string;
}
function fn3<T extends Inter>(p: T): number{
return Number.parseInt(p.name);
}
// 接口实现类
class CImpl implements Inter{
name: string;
constructor(name: string){
this.name = name;
}
}
fn3<CImpl>(new CImpl('2'));
两种文件类型
.ts文件
- 包含类型信息和可执行代码
- 可以变编译为.js 文件,执行代码
- 用途:编写程序代码的地方
.d.ts文件
- 只报销类型信息的类型声明文件
- 不会生成.js文件,仅用于提供类型信息
- 用途:为js提供类型信息
网友评论