diff --git a/chapter2/2_4_2.ts b/chapter2/2_4_2.ts index e69de29..2de62fb 100644 --- a/chapter2/2_4_2.ts +++ b/chapter2/2_4_2.ts @@ -0,0 +1,22 @@ +//对象 + +interface paintOption { + shape: "circle" | "square"; + xPos?: number; + yPos?: number; +} + +function paintShape({ shape, xPos = 0, yPos = 0 }: paintOption) { + console.log(shape, xPos, yPos); +} + +paintShape({ shape: "circle", xPos: 100, yPos: 100 }); +paintShape({ shape: "circle" }); +paintShape({ shape: "square", yPos: 100 }); + +//泛型定义类型 +interface Box { + content: T +} +let myBox: Box = { content: "hello" }; + diff --git a/chapter2/2_5.ts b/chapter2/2_5_1.ts similarity index 100% rename from chapter2/2_5.ts rename to chapter2/2_5_1.ts diff --git a/chapter2/2_5_2.ts b/chapter2/2_5_2.ts new file mode 100644 index 0000000..0da8977 --- /dev/null +++ b/chapter2/2_5_2.ts @@ -0,0 +1,57 @@ +//泛型 + +//keyof +//一个泛型参数来约束另一个泛型参数 如下面,我们约束 Key得是T的属性之一 +function getProperty(obj: T, keyName: Key) { + return obj[keyName]; +} + +let user = { + name: "Tom", + age: 12 +} +console.log(getProperty(user, "name")); //Tom + +//泛型引入构造函数 +class User { + name = "Tom"; + age = 12; + constructor() { + } + sayHello() { + console.log("hello", this.name); + } +} + +function create(con: new () => T): T { + return new con(); +} + +create(User).sayHello(); + + +//索引类型 +type Person = { age: number, name: string, alive: boolean } +type KSet = keyof Person; //"age"|"name"|"alive" +type Age = Person["age"]; +type ValueSet = Person[KSet]; //number | string | boolean Person[keyof Person] + +let a: Age = 12; +let b: KSet = "age"; +let c: ValueSet = true; + + +const MyArray = [ + { name: "Alice", age: 15 }, + { name: "Bob", age: 23 }, + { name: "Eve", age: 38 }, +]; + +type Person2 = typeof MyArray[number]; +let d: Person2 = { + name: "Hello", + age: 15 +} + + + diff --git a/chapter3/3_1.ts b/chapter3/3_1.ts new file mode 100644 index 0000000..a0bc5fe --- /dev/null +++ b/chapter3/3_1.ts @@ -0,0 +1,80 @@ +// 条件类型 +//ts的条件类型就是可以判断一个类型是否继承自另一个类型 但这个三元表达式只能返回类型,也即赋值给type +// SomeType extends OtherType ? TrueType : FalseType; + +class Animal300 { + +} +class Dog extends Animal300 { + +} + +type example = Dog extends Animal300 ? number : string; + +//不行 +// let a:example = "123" +//可以 +let a: example = 123; + +//看一个更复杂的例子 +interface IdLabel { + id: number; +} +interface NameLabel { + name: string; +} +//与泛型一起用 可以看到ts的类型系统很复杂 +type NameOrId = T extends number ? IdLabel : NameLabel; +function createLabel(idOrName: T): NameOrId { + if (typeof idOrName === 'number') { + return { + id: idOrName + } as NameOrId + } else { + return { + name: idOrName + } as NameOrId + } +} + +let result1: NameLabel = createLabel("hello"); +let result2: IdLabel = createLabel(11); + +//与泛型一起 做类型约束 +//如下代表:如果泛型T包含属性message,则MessageOf代表T["message"]的类型,否则MessageOf代表never +type MessageOf = T extends { message: unknown } ? T["message"] : never; +//如: +interface User300 { + name: string; + length: number; + message: string +} +interface User301 { + name: string; + length: number; +} +//其中就是string +let str: MessageOf = "hello"; +//下面就不能将string赋值给never +// let neverX: MessageOf = "11"; + +//再看个例子,如果类型T是数组,则Flatten是数组元素类型,否则Flatten是T本身类型 +type Flatten = T extends any[] ? T[number] : T; +let userArray = [ + { name: "hello", age: 123 }, + { name: "hello2", age: 1234 }, + { name: "hello3", age: 12345 } +] +let user: Flatten = { + name: "hello", + age: 123 +} +let ageXX: Flatten = 123; + + +//将T扩展成数组 +type toArray = T extends any ? T[] : never; +type strArrayOrNumberArray = toArray; //string[] | number[] + +let strArray: strArrayOrNumberArray = ["1234", "2345", "3456"]; +let numberArray: strArrayOrNumberArray = [1234, 2345, 3456]; \ No newline at end of file diff --git a/chapter3/3_2.ts b/chapter3/3_2.ts new file mode 100644 index 0000000..f2dc2b2 --- /dev/null +++ b/chapter3/3_2.ts @@ -0,0 +1,85 @@ +//映射类型 +//在说映射类型前 再聊下索引签名 在ts中核心解决的是如何描述一个数据结构的类型 +//索引签名解决的是 对于一个尚未声明的结构,我们如何规范这个结构,假设我现在有一个user对象,如何规范这个user呢? + +type UserIndex = { + [key: string]: string +} +//如上 我们规定结构UserIndex必须是key是string value也是string类型,比如: +let user320: UserIndex = { + name: "Tom" +} +//上面这个是ok的,但如果我们写成: +// let user321: UserIndex = { +// age: 12 +// } +// 就不行 +//我们可以通过索引类型拿到一个已知对象的value类型: +let user302 = { + name: "hello", + age: 123, + alive: true +} +//此时User302Type就是 string | number | boolean +type User302Type = (typeof user302)["name" | "age" | "alive"]; +//索引类型的核心是通过索引拿到value的类型,还可以通过keyof这样 这种情况与上面的结果一样 keyof就是上面的"name" | "age" | "alive" +type User302Type1 = (typeof user302)[keyof typeof user302]; + +//索引类型+泛型 = 映射类型 +type OptionsFlags = { + [Property in keyof T]: boolean; +} +//我们分析下上例: +//keyof T是拿到类型T的每个属性 property就是上面的每个属性 并将每个属性变为boolean,举个例子: +interface User303 { + name: string, + age: number +} +//上面我们定义了name和age两个属性,分别是string和number,但通过OptionsFlags一转化 +//得到的新属性其实是:{name:boolean,age:boolean} 将上面这些属性的类型都改为了boolean 属性名保留,类型被替换了 +type User303Flag = OptionsFlags; +let user303FlagObj: User303Flag = { + name: true, + age: false +} +//所以映射修改器就是将原来Type内属性的类型改为其他类型 +//同时映射属性还可以修改可选性?与可变性readOnly 改变的意思是可以添加或者删除 也即添加上可选性/可变性 或者删除可选性 可变性 https://www.typescriptlang.org/docs/handbook/2/mapped-types.html +type OptionsFlags2 = { + [property in keyof T]?: T[property]; +} +//可以不写任何属性,因为都是可选 +let user303FlagObj2: OptionsFlags2 = { +} + +//除了可以更改value类型,还可以通过as 更改属性名字: +//Capitalize是ts中的类型操作符,用于在类型层面将字符串类型的首字母大写 如:type small = "hello" type CapitalizedSmall = Capitalize; // 类型为 'Hello' +//而string&property是明确告诉Capitalize我的property是string类型的 +type ToGetter = { + [property in keyof T as `get${Capitalize}`]: () => T[property]; +} + +interface User304 { + name: string, + age: number +} +type UserGetter = ToGetter; +let userGetterObj: UserGetter = { + getName() { + return "hello"; + }, + getAge() { + return 12; + } +} + +//Exclude操作符可以删除某些属性 +type ExcludeType = { + [property in keyof T as Exclude]: T[property] +} + +//删除name属性 这个还是挺普遍用的,可以传入两个参数,来删除指定类型的指定属性 +type ExcludeUser304 = ExcludeType; +let excludeUser304Obj: ExcludeUser304 = { + age: 12, +} + diff --git a/chapter4/4_1.ts b/chapter4/4_1.ts new file mode 100644 index 0000000..d5ba362 --- /dev/null +++ b/chapter4/4_1.ts @@ -0,0 +1,16 @@ +interface User400 { + name: string, + sayIt: () => void; +} + +//函数加了this挺麻烦的,有些类似于go中的方法,函数绑了对象 +//这种时候只能通过对象.函数名()调用 +function sayHello(this: User400) { + console.log(this.name); +} + +let user400: User400 = { + name: "Tom", + sayIt: sayHello +} +user400.sayIt(); diff --git a/test/test.ts b/test/test.ts new file mode 100644 index 0000000..b766b77 --- /dev/null +++ b/test/test.ts @@ -0,0 +1,82 @@ +interface User { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + name: string; + company: string; + blog: string; + location: string; + email: null; + hireable: null; + bio: string; + twitter_username: null; + public_repos: number; + public_gists: number; + followers: number; + following: number; + created_at: string; + updated_at: string; +} + + +async function test() { + let url = 'https://api.github.com/users/coderzoe'; + let response = await fetch(url) + let user: User = await response.json(); //通过js的强类型 + console.log(user.login); +} + + +async function process() { + let url: string = "https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100"; + const response = await fetch(url); + const reader = response.body!.getReader(); + // console.log('aaa', response.headers.get("Content-Length")); + console.log('aaa', response.headers.get("Transfer-Encoding")); + const totalLength = Number(response.headers.get("Content-Length")); + let received = 0; + while (true) { + const { done, value } = await reader!.read(); + if (done) { + console.log(`总共需要接收${totalLength},现在接收${received}`); + break; + } + received += value.length; + console.log(`总共需要接收${totalLength},现在接收${received}`); + } +} + + +async function abort() { + let controller = new AbortController(); + controller.signal.addEventListener("abort", event => { + console.log("任务停止"); + }); + let url = "https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100"; + let response = await fetch(url, { + signal: controller.signal + }); + setTimeout(() => { + //调用终止操作 + controller.abort(); + }, 100); + +} +test() +process(); +abort(); \ No newline at end of file