TS学习笔记
类型
类型 | 例子 | 描述 |
---|---|---|
number | 1,2,-2 | 任意数字 |
string | 'hi',"hi" | 任意字符串 |
boolean | true,false | 布尔值或者true false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值(undefined) | 没有值或者undefined |
never | 没有值 | 不能是任意值 |
array | [1,1,2] | 任意js数组 |
object | {name:"孙悟空"} | 任意js对象 |
tuple | [4,5] | 元素,TS新类型,固定长度的数组 |
enum | enum{A,B} | 枚举,TS新类型 |
接口interface与类型别名type
区别:
接口,只能为对象指定类型
类型别名,不仅可以给对象指定类型,实际上可以为任意类型指定别名
//接口
interface IPerson = {
name: string
age: number
sayHi(): void
}
// 类型别名
type IPerson = {
name: string
age: number
sayHi(): void
}
let person: IPerson = {
name: '刘老师',
age: 18,
sayHi() {}
}
//类型别名
type NumStr = number | string
let numStr: NumStr = 33
let numStr2: NumStr = '66'
字面量类型
思考以下代码,两个变量的类型分别是什么?
let str1 ='Hello Ts'
const str2 : 'Hello Ts'
通过 TS 类型推论机制,可以得到答案:
\1. 变量 str1 的类型为:string。
\2. 变量 str2 的类型为:'Hello TS'。
解释:
\1. str1 是一个变量(let),它的值可以是任意字符串,所以类型为:string。
\2. str2 是一个常量(const),它的值不能变化只能是 'Hello TS',所以,它的类型为:'Hello TS'。
注意:此处的 'Hello TS',就是一个字面量类型。也就是说某个特定的字符串也可以作为 TS 中的类型。
除字符串外,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用。
let str1 = 'Hello TS'
const str2: 'Hello TS' = 'Hello TS'
let age: 18 = 18
使用模式:字面量类型配合联合类型一起使用。
使用场景:用来表示一组明确的可选值列表。
比如,在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个。
解释:参数 direction 的值只能是 up/down/left/right 中的任意一个。
优势:相比于 string 类型,使用字面量类型更加精确、严谨
function changeDirection(direction: 'up' | 'down' | 'left' | 'right') {}
changeDirection('left')
枚举类型
//枚举
/**
*enum
*/
enum Gender {
Male = 0,//可以写=0 也可以不写
Female = 1,
}
let i1: { name: string; gender: Gender };
i1 = {
name: "孙悟空",
gender: Gender.Male,
};
console.log(i1.gender === Gender.Female);
// 枚举:
enum Direction {
Up,
Down,
Left,
Right
}
function changeDirection(direction: Direction) {}
changeDirection(Direction.Left)
枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值。
枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个。
解释:
\1. 使用 enum 关键字定义枚举。
\2. 约定枚举名称、枚举中的值以大写字母开头。
\3. 枚举中的多个值之间通过 ,(逗号)分隔。
\4. 定义好枚举后,直接使用枚举名称作为类型注解。
可以直接使用 . 来访问枚举中的成员
数字枚举 字符串枚举
枚举是 TS 为数不多的非 JavaScript 类型级扩展(不仅仅是类型)的特性之一。
因为:其他类型仅仅被当做类型,而枚举不仅用作类型,还提供值 (枚举成员都是有值的)。
也就是说,其他的类型会在编译为 JS 代码时自动移除。但是,枚举类型会被编译为 JS 代码!
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
var Direction;
(function (Direction) {
Direction["Up"] = "UP";
Direction["Down"] = "DOWN";
Direction["Left"] = "LEFT";
Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));
说明:枚举与前面讲到的字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表。
一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效。
any类型
原则上不推荐使用any类型这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)。
因为当值的类型为 any 时,可以对该值进行任意操作,并且不会有代码提示
let obj: any = { x: 0 }
// 访问不存在的属性 或者 赋值
// obj.aaa
// obj.aaa = 10
// 当作函数调用
// obj()
// 赋值给其他类型的变量
// let n: number = obj
// --
// let a
// a = 1
// a = ''
// a()
// function add(num1, num2) {}
// add(1, 2)
// add(1, '2')
// add(1, false)
解释:以上操作都不会有任何类型错误提示,即使可能存在错误!
尽可能的避免使用 any 类型,除非临时使用 any 来“避免”书写很长、很复杂的类型!
其他隐式具有 any 类型的情况:1 声明变量不提供类型也不提供默认值 2 函数参数不加类型。
注意:因为不推荐使用 any,所以,这两种情况下都应该提供类型!
unknown与any
unknown只霍霍自己 赋值给别人是不行的 而any只要跟他沾边都会被霍霍都变成any
unknown就是个类型安全的any 赋值给别人前必须做判断
let e: unknown = 'str';
let s: string;
//unknown 赋值给别人需要先判断类型
if (typeof e === "string") {
s = e;
}
//或者类型断言
s = e as string;
s = <string>e;
联合类型
let a = "male" | "female"
a = "male";
a = "female";
typeof
void never
主要用于函数返回值的确定
function fn(num): void {
if (num>0) {
return; //不应有返回值
} else {
return undefined;
}
}
function fn2(): never{
throw new Error("出错了");//就是执行不完 一定会出错
}
object 与函数结构的类型声明
一般是不用object 限制太宽泛了
let a1: object;
a1 = {}
a1 = function () {
};
//用于指定哪些属性
let b1: { name: string, age?: number }//加上问好表示属性可选
b1 = { name: '孙悟空' }
let c1: { name: string, [propName: string]: any }// [propName: string]: any表示可以有任意类型的属性
c1 = { name: "猪八戒", age: 18, gender: "male" }
//定义函数的参数结构 的类型声明
let d1: (a: number, b: number) => number;
d1 = function (a: number, b: number) { return a + b; };
array
//数组
let e1: string[];//表示字符串数组
e = ['a', 'b', 'c', 'd'];
let f1: number[];
let g1: Array<number>;
元组
长度固定的数组
//元组
/**
* 语法: [类型,类型,类型]
*/
let h1: [string, string, number];
h1 = ["hello", "world", 123];
或 | 和 与&
// | 表示或 & 表示且
let j1: { name: string } & { age: number }
j1={name: "孙悟空",age:18}
编译选项
tsc app.ts -w
-w watch模式 只监视app.ts
使用tsc 编译此项目下的全部ts文件 前提是得由tsconfig.json文件 即使这个文件为空json也会按照默认的选项来编译!
webpack打包TS
package.json 需要哪些包
{
"name": "ts-webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open "
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.18.13",
"@babel/preset-env": "^7.18.10",
"babel-loader": "^8.2.5",
"clean-webpack-plugin": "^4.0.0",
"core-js": "^3.24.1",
"html-webpack-plugin": "^5.5.0",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.10.0"
}
}
webpack.config.js 定义打包的方式
//引入路径包
const path = require("path");
//引入一个插件包
const HTMLWebpackPlugin = require("html-webpack-plugin");
//引入clean插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
//添加模式
mode: "development",
//指定入口文件
entry: "./src/index.ts",
//指定打包文件所在目录
output: {
//指定目录
path: path.resolve(__dirname, "dist"),
//指定名字
filename: "index.js",
//配置环境兼容问题
environment: {
arrowFunction:false
}
},
//指定打包时要用到的模块
module: {
rules: [
{
//test指定的是规则生效的文件
test: /\.ts$/, //匹配以ts结尾的文件
//use 要使用的loader 数组中的内容从后往前执行
use: [
{
//设置加载器
loader: "babel-loader",
//设置babel
options: {
//设置预定义的环境
presets: [
[
//指定环境的插件
"@babel/preset-env",
//配置信息
{
//要兼容的默认浏览器
targets: {
//浏览器版本
"chrome": "58",
"ie":"11"
},
//指定corejs的版本
"corejs": "3",
//使用corejs的方式
"useBuiltIns": "usage"
}
]
]
},
},
"ts-loader",
],
//exclude 排除哪些文件
exclude: /node-modules/,
},
],
},
//配置webpack的插件
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
// title: "这是一个自定义的title",
template: "./src/index.html",
}),
],
//用来设置引用模块
resolve: {
extensions: [".ts", ".js"],
},
};
tsconfig.json ts的编译方式
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
类
//使用class关键字来定义一个类
/**
* 属性
* 方法
*/
class Person{
//实例属性
name: string = "孙悟空";
//在属性前加关键字static可以定义类属性(静态属性)即不需要创建实例就可访问的属性
static age: number = 18;
//只读属性
readonly gender: string = "male";
//实例方法
say() {
console.log('hello')
}
//静态方法
static run() {
console.log('run')
}
}
const per = new Person();
console.log('per.name', per.name);
console.log('per', per);
per.say();
console.log('Person.age', Person.age)
Person.run();
构造函数与this
class Dog{
name: string;
age: number;
//构造函数
constructor(name: string, age: number) {
console.log('构造函数执行了',this)
this.name= name
this.age= age
}
bark() {
console.log('wangwangwang')
}
}
const dog = new Dog('xiaohei',4);
console.log('dog',dog)
类的继承
(() => {
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`${this.name}sayHello`);
}
}
class Dog extends Animal {
sayHello(): void {
console.log("wangwangwang"); //子类覆盖掉父类的方法的形式叫重写
}
}
class Cat extends Animal {
run() {
console.log(`${this.name}run`);
}
}
const dog = new Dog("旺财", 5);
const cat = new Cat("咪咪", 3);
console.log("cat", cat);
console.log("dog", dog);
dog.sayHello();
cat.sayHello();
cat.run();
})();
super
(() => {
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayHello() {
console.log(`${this.name}sayHello`);
}
}
class Dog extends Animal {
age: number;
constructor(name: string, age: number) {
super(name);//必须先调用父类的构造函数
age = this.age;
}
sayHello(): void {
super.sayHello(); //super表示当前类的父类
}
}
const dog = new Dog('旺财',1);
dog.sayHello();
})();
抽象类
(() => {
abstract class Animal {
//我们不希望直接用Animal来创建实例,我们只需要让它是一个超类 用来被继承
//所以我们给它加上abstract 那么这个类就只能被继承 不能用它创建实例
//抽象类可以添加抽象方法
name: string;
constructor(name: string) {
this.name = name;
}
//抽象方法只能在抽象类里定义 抽象方法没有方法体
//子类必须对抽象方法进行重写
abstract sayHello(): void;
}
class Dog extends Animal {
//非抽象类继承抽象类 必须重写父类中的抽象方法
sayHello(): void {
console.log("汪汪汪");
}
}
const dog = new Dog("旺财");
dog.sayHello();
})();
接口
(() => {
/**
* 对于类型声明(类型别名) 只能声明一次
*
* 对于接口 可以重复声明 多次声明那么创建的实例应把接口中的定义的都实现
* 接口可以限制类的结构
* 接口只定义类的结构不定义类的实际值
* 接口的所有方法都是抽象方法
*
*
*
*/
//描述一个对象的类型 类型别名
type myType = {
name: string;
age: number;
};
let obj: myType = {
name: "sss",
age: 1,
};
/**
* 接口用来定义一个对象的结构
* 用来定义一个类中应该包含哪些属性和方法
*/
interface myInterface {
name: string;
age: number;
}
interface myInterface {
gender: string;
sayHello(): void;
}
let obj1: myInterface = {//当作类型使用
name: "aaa",
age: 2,
gender: "male",
sayHello() {
console.log("hello");
},
};
//实现接口
class Myclass implements myInterface {
name = '孙悟空';
age = 18;
gender = 'male';
sayHello() {
console.log("嘿嘿")
}
}
})();
属性的封装
private getter setter
(() => {
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let per = new Person("孙悟空", 18);
console.log("per", per);
per.name = "猪八戒";
per.age = -18;
console.log("per", per); //可以任意修改 年龄能有负数嘛?
/**
* 上面的属性是在对象中设置的,属性可以任意的被修改
* 属性可以任意被修改将会导致对象中的数据会变得非常不安全
*/
class Animal {
/**q
* 可以在属性前添加修饰符
*/
public name: string; //公共属性可以在任意位置(访问)更改 默认就是public
private age: number; //私有属性 只能在类内部(访问)修改
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
//getter 添加方法让私有属性可以在外部访问
getAge() {
return this.age;
}
//setter 设置属性
setAge(value: number) {
if (value > 0) {
this.age = value;
}
}
}
let dog = new Animal("旺财", 2);
console.log("dog", dog);
console.log("dog.getAge()", dog.getAge());
dog.setAge(-8);
console.log("dog", dog); //改不了
})();
protected 与 constructor 语法糖
(() => {
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let per = new Person("孙悟空", 18);
console.log("per", per);
per.name = "猪八戒";
per.age = -18;
console.log("per", per); //可以任意修改 年龄能有负数嘛?
/**
* 上面的属性是在对象中设置的,属性可以任意的被修改
* 属性可以任意被修改将会导致对象中的数据会变得非常不安全
*/
class Animal {
/**q
* 可以在属性前添加修饰符
*/
public _name: string; //公共属性可以在任意位置 包括子类 (访问)更改 默认就是public
private _age: number; //私有属性 只能在类内部(访问)修改
//protected 受保护的属性,只能在当前类和当前类的子类中访问
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
// //getter 添加方法让私有属性可以在外部访问
// getAge() {
// return this.age;
// }
// //setter 设置属性
// setAge(value: number) {
// if (value > 0) {
// this.age = value;
// }
// }
//ts中设置获取属性 设置属性 的方法 不会改变访问数据的方法
/**
* 不是特别复杂的修改时 一般用不到
*/
get age() {
return this._age;
}
set age(value: number) {
if (value > 0) {
this._age = value;
}
}
}
let dog = new Animal("旺财", 2);
// console.log("dog", dog);
// console.log("dog.getAge()", dog.getAge());
// dog.setAge(-8);
console.log("dog.age", dog.age);
// console.log("dog", dog); //改不了
dog.age = 8;
console.log("dog", dog);
/**
* 语法糖
*/
class C {
//得用public
constructor(public name: string, public age: number) {}
}
let c = new C("666", 6);
console.log("c", c);
})();
泛型
(() => {
function fn(a: any): any {
return a;
}
/**
* 在定义函数或是类时遇到类型不明确的 可以使用泛型
*
*/
function fn1<T>(a: T): T {
//我不知道a到底是是么类型但是我知道 返回值和入参的类型时相同的
return a;
}
fn1(10); //自动推断
fn1<string>("test"); //类型断言
function fn2<T, K>(a: T, b: K): T {
console.log("b", b);
return a;
}
fn2(123, "test");
fn2<number, string>(333, "test");
interface Test {
length: number;
}
//泛型T得是Test的实现类(子类)
function fn3<T extends Test>(a: T): number {
return a.length;
}
fn3([1, 2, 2]); //传入的参数的类型得是Test接口的实现类
})();
仓库地址:https://gitee.com/bbigger004/tslearn.git
TS学习笔记的更多相关文章
- TS学习笔记----(一)基础类型
布尔值: boolean let isDone: boolean = false; 数字: number 和JavaScript一样,TS里的所有数字都是浮点数. 支持十进制和十六进制字面量,TS还支 ...
- ts 学习笔记-基础篇
目录 基础 原始数据类型 布尔值 数字 字符串 空值 Null 和 Undefined 任意值 类型推论 联合类型 接口 数组 函数 类型断言 申明文件 什么是申明文件 三斜线指令 第三方声明文件 内 ...
- ts 学习笔记 - 泛型
目录 泛型 举个栗子 泛型约束 多个参数时也可以在泛型约束中使用类型参数 泛型接口 泛型类 泛型参数的默认类型 泛型 泛型(Generics)是指在定义函数.接口或者类的时候, 不预先指定其类型,而是 ...
- ts 学习笔记 - 类
目录 类 类的概念 类的用法 属性和方法 类的继承 存取器 静态属性 Typescript 中的用法 抽象类 类的类型 类与接口 类实现接口 接口继承接口 接口继承类 混合类型 类 类的概念 类 (c ...
- ts 学习笔记 - 进阶篇 1
目录 进阶 类型别名 字符串字面量类型 元祖 例子 越界的元素 枚举 手动赋值 常数项和计算所得项 常数枚举 外部枚举 进阶 类型别名 类型别名用来给一个类型起个新名字 type Name = str ...
- Ionic2学习笔记(9):访问本地设备
作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5559927.html Ionic2提供了访问本地设备的方法,但是需要安装 ...
- Ionic2学习笔记(8):Local Storage& SQLite
作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5557947.html Ionic2可以有两种方式来存储数据,Local S ...
- Ionic2学习笔记(7):Input
作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5554610.html 我们先来看一个简单的输入用户名和密码点击登录的界面: ...
- Ionic2学习笔记(6):Navigation
作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5551535.html Ionic2中创建一个页面很方便,在页面之间相互切换也很方 ...
随机推荐
- ETL工具Datax、sqoop、kettle 的区别
一.Sqoop主要特点: 1.可以将关系型数据库中的数据导入到hdfs,hive,hbase等hadoop组件中,也可以将hadoop组件中的数据导入到关系型数据库中: 2.sqoop在导入导出数据时 ...
- CentOS 8.2 对k8s基础环境配置
一.基础环境配置 1 IP 修改 机器克隆后 IP 修改,使Xshell连接上 [root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg- ...
- Request保存作用域
Request保存作用域,作用范围是在当前请求中有效. 1.客户端重定向 2.服务器内部转发
- Vue学习之--------Vue中过滤器(filters)的使用(代码实现)(2022/7/18)
1.过滤器 1.1 概念 过滤器: 定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理). 语法: 1.注册过滤器:Vue.filter(name,callback) 或 new V ...
- 7.Gitee导入其他远程托管中心仓库
的码云是开源中国推出的基于Git的代码托管服务中心 网址是https://gitee.com/,使用方式跟github一致,并且是一个中文网站 码云的使用配置方式与github一致,码云支持导入git ...
- 三、Ocelot请求聚合与负载均衡
上一篇文章介绍了在.Net Core中如何使用Ocelot:https://www.cnblogs.com/yangleiyu/p/16847439.html 本文介绍在ocelot的请求聚合与负载均 ...
- vue传值
在vue 中组件间的传参是必不可少的,下面说下几种传参方式 1.父组件传值给子组件,首先父组件发送的形式是用bind(用缩写:)绑定值到子组件身上.然后子组件用属性props接收 2.子组件传值父组件 ...
- centos使用lftp备份文件
一直以来项目的文件没有备份,最近需要增加备份,本来以为备份是IT的工作,结果IT说工作忙,拖了半个月给分配完ftp服务器后说不给备份,需要我们开发自己备份...我特么*** 对于ftp备份,咱是没有经 ...
- 微信小程序的学习(一)
一.小程序简介 1.小程序与普通网页开发的区别 运行环境不同 网页运行在浏览器环境中 小程序运行在微信环境中 API不同 小程序无法调用浏览器中的DOM和BOM的API 但是小程序可以调用微信环境提供 ...
- JavaScrip基础学习笔记(一)
一.三元表达式 1.1 什么是三元表达式 由三元运算符组成的式子我们称为三元表达式 1.2 语法结构 条件表达式 ? 表达式1 : 表达式2 1.3 执行思路 如果表达式为结果真 则返回表达式1的值, ...