typescrip学习笔记2
typescrip学习笔记
准备
需要安装的依赖
npm install -g typescript
// 查看安装成功
tsc -v
npm install -g ts-node
需要的插件
Code Runner
生成配置文件
tsc --init
ts中的数据类型
变量的声明的几种类型
// 1. 声明变量并赋值
let username: string = 'ywj';
// 2. 声明变量, 无初始值, 会设置为 undefined, 赋值前不能使用, 如log
let username1: string;
// 3. 有初始值, 不设置类型, 可以是任意类型
let username2 = '12345';
// 4. 没设置初始值, 没有类型, 类型可以是任意类型, 默认初始值 undefined
let username3;
数字类型
// 02 ts的数据类型
// 1. 数字类型 number 可以是二进制, 8, 10, 16进制
let bin: number = 0b1011
let octa: number = 0o11
let ten: number = 8
let hex: number = 0x11
字符串类型
// 2. 字符串类型
let userStr: string = '这是一个str'
let resStr: string = `这是${userStr}`
布尔类型
// 3. 布尔类型 true/false
let flag: boolean = true
let flag1: boolean = false
数组类型
// 03 数组类型
let arr: string[] = ['呵呵', '嘻嘻', '哈哈']
let arr2: Array<string> = ['呵呵', '嘻嘻', '哈哈']
元组
// 04 元组 : 数组里面规定元素的类型和位置
let yuan: [string, number, boolean]
yuan = ['呵呵', 16, true]
枚举
// 05 枚举(enum) 一般大写
enum Color { Red = 11, Green = 23, Aqua = 45 }
// enum Color { Red, Green, Aqua }
let color: Color = Color.Green
// console.log(color) // 这里输出为1, 设置值之后 23 这里的数字有些讲究
// 如果有人拿这里做文章, 建议直接掀桌子
void
// 06 void类型. 用于标识方法返回值的类型, 标识该方法没有返回值
function say(): string {
return ''
}
function say1(): void {
return
}
// 实际上viod函数也可以有返回值, 并且不会报错
null类型
// 07 null类型
let nobj: null = null
// console.log(typeof nobj); // 这里是 object
undefined
// 08 undefined 是没有赋值的变量
// typeof 一个没有赋值的变量 就会返回 undefined
// null 和 undefined 可以赋值给其他任意类型 严格的空校验下不行. 能不用尽可能不用, 没必要
any类型
// 09 any类型 表示任意类型
let anyType: any = 123
anyType = 'hehehe'
anyType = true
anyType.say() // 无中生有也行
let anyArr: any[] = [123, 'xixi', false]
复杂数据类型
联合类型
// 联合类型 使用 | 隔开
let lname: number | string
lname = 123
lname = 'ywj'
// lname = true // 报错
let larr: number | number[]
larr = 123
larr = [1, 2, 3]
let larr1: number[] | string[]
larr1 = [1, 2, 3]
larr1 = ['1', '2', '3']
// 作为函数的参数
function lfn(sum: number | number[]): void {
// do something
}
接口
// 接口
interface Person {
name: string,
age: number,
say: () => string,
show(): void
}
let p1: Person = {
name: 'ywj',
age: 18,
say: () => {
return 'ywj is handsome!!!'
},
show() {
console.log('xixi');
return ';h'
}
}
// Student 里面需要有Person里面的所有属性
class Student implements Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
say() {
return 'hehe'
}
show() {
// 这里为啥可以返回?
return '123'
}
}
接口继承
// 接口的继承
interface Person1 {
name: string,
age: number,
}
interface Musicia extends Person1 {
use: string
}
let p2: Musicia = {
name: 'ywj',
age: 18,
use: 'gita'
}
class Student1 implements Musicia {
name: string
age: number
use: string
constructor(name: string, age: number, use: string) {
this.name = name
this.age = age
this.use = use
}
}
// let p3: Musicia = {} // 这个会直接报错
// let p3 = {} as Musicia // 这个同下, 不会报错
let p3 = <Musicia>{}
p3.age = 19
p3.name = 'ywj'
p3.use = 'piano'
console.log(p3);
ts中的类
-
ts中的class包括: 属性, 构造函数, 方法
class Person2_copy { static sex: string = 'sex' // 添加static属性之后, 就是一个静态属性, 不属于这个对象, 调用的时候直接用类名 user: string // age: number constructor(user: string, age: number) { this.user = user this.age = age } say(): string { return '123' } }
-
简单的类, 属性直接赋值, 可以不用构造函数
class Person2 { // 直接这样写就不用构造函数了 user: string = 'ywj' age: number = 18 }
-
属性和方法用static方法修饰的, 称为静态方法不属于new出来的对象,不能使用obj.属性来访问, 主持能通过类名来访问
let p4 = new Person2_copy('ywj', 18) console.log(p4.sex) // 这个报错 console.log(Person2_copy.sex);
-
ts类中的修饰符, public, private, protected
// public(默认): 可以在任意地方访问 // protected: 受保护, 可以被自身及其子类访问, 不能在被new出来的对象中访问 // private: 私有, 自能在自定义的类中访问, 不能在被new出来的对象中访问
-
类本身就是一种类型
class Person { name: string constructor(name:string) { this.name = name } } let p1:Person = new Person('ywj')
-
小tips, 如果constructor中的变量使用了public修饰, 在方法中可以直接使用.变量名访问
class Person { constructor(public name:string) {} } // 上面相当于 class Person { name: string constructor(name:string) { this.name = name } }
类的继承
-
使用extend继承
class A { user: string private age: number constructor(user: string, age: number) { this.user = user this.age = age } show(): string { return this.user } } class B extends A { hobby: string constructor(hobby: string, user: string, age: number) { super(user, age) this.hobby = hobby } }
-
子类继承父类属性需要使用super(), 并传参
class B extends A { hobby: string constructor(hobby: string, user: string, age: number) { super(user, age) this.hobby = hobby } }
-
父类中使用private修饰的属性, 子类访问不了
const b1 = new B('千代', 'ywj', 18) console.log(b1.age); // 报错
泛型
-
作用:允许在函数, 类, 接口上面, 使用占位符来表示类型, 而不是具体的类型 主要目的: 处理不特定类型的数据
-
泛型就相当于一个代表类型的参数, 使用的时候需要输入具体类型
-
函数中使用
// T表示类型的占位符, a, 和b 都是 T类型的数据 function fn1<T>(a: T, b: T): T[] { return [a, b] } let a1: number[] = fn1<number>(1, 2) console.log(a1); let a2: string[] = fn1<string>('hehe', 'xixi') console.log(a2); // 上面的T是一个类型的占位符 // 使用的时候, 需要指定T的具体类型
-
接口中使用
// 在接口中使用 interface P2<T, K> { name: T, age: K } let pp2: P2<string, number> = { name: 'ywj', age: 18 }
-
类中使用
class P3<T, K> { name: T age: K constructor(name: T, age: K) { this.name = name this.age = age } getInfo(): T { return this.name } } let pp3: P3<string, number> = new P3<string, number>('ywj', 18)
泛型约束
控制泛型的类型范围
用法
// 这里的T只能是string 或 number
// T extends string 这个表示只能是 string
function fn1_copy<T extends string | number>(a: T, b: T): T[] {
return [a, b]
}
泛型与接口联合使用
interface Msg {
name: string,
age: number
}
let p8: Msg = {
name: 'ywj',
age: 18
}
// 这里的T是Msg的健 name 或 age中的其中一个
function getmsg<T extends keyof Msg>(msg: Msg, key: T): Msg[T] {
return msg[key]
}
let res = getmsg(p8, 'age')
console.log(res);
装饰器
作用: 不改变原代码的前提下 实现在原有逻辑代码的前后增加功能
类装饰器(ClassDecorator)
用法: 给class上面加上注解
例如: 给类添加一个属性和方法
注意后面使用的时候, 需要使用断言as any
下面这个是没有传参的情况
// 这里面的fn是Ss的构造函数
const app: ClassDecorator = (fn): void => {
// console.log(fn, '111');
fn.prototype.age = 18
fn.prototype.say = () => {
console.log('一直18岁');
}
}
// 这玩意就是注解 @app
@app
class Ss {
name: string
constructor(name: string) {
this.name = name
}
}
let s1: Ss = new Ss('ywj')
// console.log(s1.constructor);
// console.log(s1.age); // 直接访问age报错
// 这里要用断言(s1 as any)
console.log((s1 as any).age);
(s1 as any).say()
需要传参的情况
const app = (address: string): ClassDecorator => {
return (fn): void => {
// console.log(fn, '111');
fn.prototype.age = 18
fn.prototype.address = address
fn.prototype.say = () => {
console.log('一直18岁');
}
}
}
@app('北京以北')
class Ss {
name: string
constructor(name: string) {
this.name = name
}
}
let s1: Ss = new Ss('ywj')
// 这里要用断言(s1 as any)
console.log((s1 as any).age);
console.log((s1 as any).address);
方法装饰器(MethodDecorator)
用法: 给方法上面加上注解
在new对象的时候执行
需要注意的是:
- 使用方法是在方法的上一行加上@get
- 方法3个参数, 没有返回值
- target表示对象本身, 能通过target访问方法,调用方法(通过断言) 不能访问属性
- propertyKey表示方法名称
- descriptor表示方法的解构, 可以通过descriptor.value()调用方法, 也可以传参
- class本身也能作为一种类型
const get: MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void => {
console.log(1, target); // 目标对象
console.log(2, propertyKey); // 方法名
console.log(3, descriptor); // 方法的结构
// console.log(4, (target as Demo1).user); // undefined 获取不到属性
// (target as Demo1).getData('www.hehe.com') // 可以通过target来调用
descriptor.value('12345') // 可以通过这个调用方法, 也能传参
console.log('上山打老虎');
}
class Demo1 {
user: string
constructor(user: string) {
this.user = user
}
// 这个是在对象生成的时候执行
@get
getData(url: string) {
console.log(url);
}
}
let d1: Demo1 = new Demo1('ywj')
d1.getData('颗粒大魔王')
传参的情况
注意写法
const get = (url: string): MethodDecorator => {
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void => {
console.log(url, 'url');
descriptor.value(url) // 可以通过这个调用方法, 也能传参
console.log('上山打老虎');
}
}
class Demo1 {
user: string
constructor(user: string) {
this.user = user
}
// 这个是在对象生成的时候执行
@get('www.ywj is handsome .com')
getData(url: string) {
console.log(url);
}
}
ts模块
定义模块 math.ts
导出使用 export
export function add(a: number, b: number): number {
return a + b
}
export function delt(a: number, b: number): number {
return a - b
}
使用模块
导入使用 import {} from 模块
可以有两种方法
方法1
import { add, delt } from "./math";
console.log(add(1, 2));
方法2
import * as math from './math'
console.log(math.add(2, 3));
console.log(math.delt(2, 3));
引用时起别名
import {addition as add} from 'xx'
add(1,2)
如果导出的模块中有export default, 导入的时候就不用解构了, 直接
import 模块名 from 'XX'
// 模块名 可以随便写, 但别太随便
小练习
目标: 模拟后台获取一些数据, 显示在页面
准备: 一个data.json文件, 一个index.ts文件, 一个index.html文件
注意, index.html中不能直接引入index.ts, 需要将index.ts编译成index.js
命令 -- 注意要跳转到目标文件夹下
tsc index.ts
需要注意的是
- fetch是浏览器自带的, 返回一个promise, 封装的时候, 没有返回值可需要给个Promise
- 分析数据结构, 先从data里面对象数组的结构开始, 一步一步向外面定义数据类型, 可以使用泛型
, 会方便 - 获取到的数据需要.json一下
- div也是有type的, HTMLDivElement
- 最后编译的时候报错了, 但是编译成功了
data.json
{
"code": 200,
"data": [
{
"user": "ywj1",
"age": 18
},
{
"user": "littleship",
"age": 16
}
],
"msg": "ok"
}
index.ts
interface DateType {
user: string
age: number
}
interface ResType<T> {
code: number,
data: T[],
msg: string
}
// fetch('./data.json')
// .then((res: Response) => res.json())
// .then((res: ResType<DateType>) => {
// console.log(res.data[0]);
// let app: HTMLDivElement = document.querySelector("#app") as HTMLDivElement
// res.data.forEach((item: DateType) => {
// let div1: HTMLDivElement = document.createElement('div') as HTMLDivElement
// div1.innerHTML = `<span style="margin-right: 20px">姓名: ${item.user}</span><span>年龄: ${item.age}</span>`
// app.append(div1)
// })
// })
async function getList(): Promise<void> {
let response: Response = await fetch('./data.json')
let res: ResType<DateType> = await response.json()
let app: HTMLDivElement = document.querySelector("#app") as HTMLDivElement
res.data.forEach((item: DateType) => {
let div1: HTMLDivElement = document.createElement('div') as HTMLDivElement
div1.innerHTML = `<span style="margin-right: 20px;color: aqua">姓名: ${item.user}</span><span>年龄: ${item.age}</span>`
app.append(div1)
})
}
getList()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>typescript</title>
<script src="index.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
感谢
特别感谢Ju加油坊老哥
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2022-06-27 10. watch的实现原理
2022-06-27 9. 计算属性的实现原理
2022-06-27 8. 数组更新的实现原理
2022-06-27 7. mixin的实现原理