TypeScript 开源教程,介绍基本概念和用法,面向初学者。
wangdoc / typescript-tutorial Goto Github PK
View Code? Open in Web Editor NEWTypeScript 教程
Home Page: https://wangdoc.com/typescript
TypeScript 教程
Home Page: https://wangdoc.com/typescript
https://wangdoc.com/typescript/
这个路径跳转到typescript文档的链接,现在指向到Web Api 文档了
You can rename d.ts.md to d_ts.md
原文:
注意,模板字符串可以引用的类型一共6种,分别是 string、number、bigint、boolean、null、undefined。引用这6种以外的类型会报错。
事实上,经过我测试,引用这六种之外的枚举类型,不会报错,可以解析。
例子:
enum e2 {
a = 'a',
b = 'b'
}
type t = w ${e2}
// "w a" | "w b"
故此,望改正。
你的读者
2024年3月19日
似乎沒有在教程中找到關於 satisfies 運算子的描述
原文:
class C {
accessor x = 1;
}
上面示例中,accessor修饰符等同于为属性x自动生成取值器和存值器,它们作用于私有属性x。也就是说,上面的代码等同于下面的代码。
class C {
#x = 1;
get x() {
return this.#x;
}
set x(val) {
this.#x = val;
}
}
上述示例中,经过 accessor
修饰的 x
并不会转化为私有属性。
class C {
accessor x = 1;
accessor #y = 1;
}
const c = new C();
console.log(c.x);
console.log(c.y);
// ^? 此处访问 c.y 会报错
阮老师您好。我是您的一名小读者。原文,在 ./docs/declare.md
typescript-tutorial/docs/declare.md
Line 305 in d8b2606
下面的示例是为 window 对象添加一个属性`myAppConfig`。
```typescript
export {};
declare global {
interface window {
myAppConfig: object;
}
}
const config = window.myAppConfig;
```
declare global 里 interface 后面的 window 的首字母 w 似乎需要大写,才能让 TS 识别接口类型。我这边 TS 版本是5.3.2。不知道这算不算一个问题呢?
如果一个对象的所有属性都是可选的,会触发最小可选属性规则。
type Options = {
a?:number;
b?:number;
c?:number;
};
const obj:Options = {
d: 123 // 报错
};
上面示例中,类型Options是一个对象,它的所有属性都是可选的,这导致任何对象实际都符合Options类型。
为了避免这种情况,TypeScript 添加了最小可选属性规则,规定这时属于Options类型的对象,必须至少存在一个可选属性,不能所有可选属性都不存在。这就是为什么上例的myObj对象会报错的原因。
原文示例會報錯的原因是 d 不存在於 Options 類型中,並不是因為 最小可选属性规则
type Options = {
a?: number;
b?: number;
c?: number;
};
// 沒有錯誤
const obj1: Options = {}
declare function parseOption(options: Options): void
// 仍然報錯
parseOption({ a: 1, d: 1 })
// 沒有錯誤
parseOption({})
第11章类第8节抽象类,抽象成员部分关于抽象方法那里“如果抽象类的属性前面加上abstract,就表明子类必须给出该方法的实现。“应该是”如果抽象类的方法前面加上abstract,就表明子类必须给出该方法的实现。
const sym1:symbol = Object(Symbol('tset'))
我发现这样写,并没有报错。但按文档而言,这样获取的是包装类型,小写的symbol类型是不正确的?这里是不是有问题
章节:
https://wangdoc.com/typescript/types#boolean-%E7%B1%BB%E5%9E%8B
问题:
变量x和y就属于 boolean 类型。
修正:
常量x和y就属于 boolean 类型。
后面也有类似问题,如
章节:
https://wangdoc.com/typescript/types#bigint-%E7%B1%BB%E5%9E%8B
问题:
上面示例中,变量x和y就属于 bigint 类型。
修正:
上面示例中,常量x和y就属于 bigint 类型。
这一小段有点问题,https://wangdoc.com/typescript/types#undefined-%E7%B1%BB%E5%9E%8Bnull-%E7%B1%BB%E5%9E%8B。
开启了strictNullChecks,const b = undefined 应该被推断为undefined类型,const d = null 应该推断为 null类型。
具体原因不懂,个人认为是因为const定义的变量不可修改,所以定义时就可以推断出类型。
TypeScript 允许将tsc
的编译参数,写在配置文件tsconfig.json
。只要当前目录有这个文件,tsc
就会自动读取,所以运行时可以不写参数。
$ tsc file1.js file2.js --outFile dist/app.js
应该为
$ tsc file1.ts file2.ts --outFile dist/app.js
大神,类型断言那一章,联合类型断言
const s1:number|string = 'hello'; const s2:number = s1 as number; // 报错
值实际是字符串断言成number会报错, 应该断言成字符串,或者用unkonwn中转一下断言成number
const s2:string= s1 as string; const s22: number = s1 as unknown as number
在教程中提到:
可选属性等同于允许赋值为undefined,下面两种写法是等效的。
但是我在实际操作中发现,教程中提到的两种写法不完全等效。为方便区分,我将User类型的两种写法修改为User1 和 User2.
type User1 = {
firstName: string;
lastName?: string;
};
// 不完全等同于
type User2 = {
firstName: string;
lastName: string|undefined;
};
//创建对象,类型为User1,对象字面量中仅包含firstName属性。 type 为User1 不会报错,因为lastName为可选属性
const user1 : User1 = {
firstName: "alan",
}
//type为User2 会报错,因为lastName 值可以为string或undefined,但是不可省略 ,即 "lastName" in user2 应当返回true
const user2 : User2 = {
firstName: "alan",
}
//允许如下方式定义类型为User2 的对象
const user3 : User2 = {
firstName: "alan",
lastName:undefined
}
// 推断为 any[]
const arr = [];
// 推断类型为 number[]
arr.push(123);
// 推断类型为 (string | number)[]
arr.push('abc');
数组的类型推断 - 网道
如上所示,在 ts playground 和 vscode 中测试,arr
在添加了 number
和 string
之后,仍然被推断为 any[]
。
阮老师您好,经测试函数的readonly参数只能修饰数组和元组类型,文档是否要说明一下?
x y互相赋值的例子后,
原文:上面示例中,变量x属于子类型,变量y属于父类型。子类型x不能赋值为父类型y,但是反过来是可以的。
如果一定要让子类型可以赋值为父类型的值,就要用到类型断言(详见《类型断言》一章)。
这两处表述是否有误。
从我自己使用经验,我真的体会到ts有时候不那么好用,引入的问题比起要解决问题反而更麻烦,举几个例子
The short version is that no one has implemented the types for fetch in this package yet. There are some ideas about how best to handle it but I don't know if there is actually a consensus among maintainers of this package. If you'd like to help with that, DT has good guidelines for getting started as a contributor, and I'm sure several people on this thread would be eager to review a MR.
let options = {
foo: 'bar',
bar: 'baz',
}
for (const [key, value] of process.argv) {
if (key in options) {
options[key] = value; // 报错,尽管我已经在if 里
}
}
进一步数组的 reduce 方法标注就会变得很复杂,参见 https://stackoverflow.com/questions/52856496/typescript-object-keys-return-string
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"outDir": "dist",
"strict": true,
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
举例来说,Web 网页开发经常会对
windows
对象和document
对象添加自定义属性,但是 TypeScript 会报错,因为原始定义没有这些属性。解决方法就是把自定义属性写成 interface,合并进原始定义。
interface Document {
foo: string;
}
document.foo = 'hello';
error TS2339: Property 'foo' does not exist on type 'Document'.
作者您好,首先感谢您的付出。
我在阅读过程中有一点疑惑,为什么某些doc目录下的md没有被加到chapters.yml,进而也没有显示在网站上,如react.md。
请问是有什么特殊考量吗?
谢谢。
“语言简介(intro.md)”中。
“上面示例中,例一的报错是因为变量一旦赋值了,就不允许再改变类型”,这段描述可能有问题。
变量的类型确定,应该是在变量声明的时候,而不是赋值的时候。
// 这段代码可以通过编译,因为在第一行 c 已经被推断为 any 类型(这只是我的猜测)
let c;
console.log(typeof c);
c = 1;
console.log(typeof c);
c = '1';
console.log(typeof c);
在第四章《类型系统》2.2小节最后一段话,描述symbol类型和bigint包装对象时,有如下描述:
上一小节说过,Symbol()和BigInt()这两个函数不能当作构造函数使用,所以没有办法直接获得 symbol 类型和 bigint 类型的包装对象,因此Symbol和BigInt这两个类型虽然存在,但是完全没有使用的理由。
这句话有点小小的错误。实际上,在javascript中,使用Object()方法传递一个symbol值返回的就是一个symbol类型的包装对象,传递一个bigint类型的值Object()函数返回的就是一个bigint类型的包装对象。
阮老师,这里的const 应该为type
@ruanyf
// @ts-ignore或// @ts-expect-error,告诉编译器不对下一行代码进行类型检查,可以用于 TypeScript 脚本,也可以用于 JavaScript 脚本。
@ts-ignore 和 @ts-expect-error 的用法並不相同
如果 // @ts-expect-error 下一行沒有錯誤,那麼在註釋行會出現錯誤
Unused '@ts-expect-error' directive.
类的内部可以使用staic关键字,定义静态成员。
d.ts这一章配置的地址错误
$ tsc --outFile result.js b.ts
弄好文件之后,我运行了上面的命令,出现如下错误
Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.
之后我尝试指定值,amd 或 system
结果发现出现的代码无法直接在浏览器运行。
这是一个错误。
如果您认同我的想法,希望尽快改正,感谢您的文档,您的文档yyds
现在白底晚上看太晃眼了,希望参考一下vue官网那种,可以切换暗黑模式,或者可以实现自动根据时间切换主题
https://wangdoc.com/typescript/any#%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%E9%97%AE%E9%A2%98
这里const声明时必须赋值,应该是Javascript要求的,ts只是做类型检查
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"outDir": "dist",
"strict": true,
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
第二个方法是使用 import type 语句,这个语句只能输入类型,不能输入正常接口。
// 正确
import type { A } from './a';
// 报错
import type { a } from './a';
上面示例中,import type 输入类型A
是正确的,但是输入正常接口a
就会报错。
正常引入第二个语句 import type { a } from './a';
时不会报错, 作为类型使用时也能正常使用,作为非类型的值使用时才会报错。例如:
import type { a } from './2'
type C = typeof a //正常
import type { a } from './2'
let c = a //报错: "a" 是使用 "import type" 导入的,因此不能用作值。ts(1361)
原文:
Enum 结构的特别之处在于,它既是一种类型,也是一个值。绝大多数 TypeScript 语法都是类型语法,编译后会全部去除,但是 Enum 结构是一个值,编译后会变成 JavaScript 对象,留在代码中。
// 编译前
enum Color {
Red, // 0
Green, // 1
Blue // 2
}
// 编译后
let Color = {
Red: 0,
Green: 1,
Blue: 2
};
然而,这里的 Color
符合文末的“反向映射”中的内容:
数值 Enum 存在反向映射,即可以通过成员值获得成员名。
TypeScript playground 的编译结果符合反向映射中的结果:
"use strict";
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue"; // 2
})(Color || (Color = {}));
所以前面的“编译后”内容是否可以认为是不准确的?
阮老师您好。发现2个小拼写问题。
typescript-tutorial/docs/tsconfig.json.md
Line 159 in f77f8d1
typescript-tutorial/docs/utility.md
Line 470 in f77f8d1
图中地址:点我跳转
这里的描述是否有失偏颇? 如果按照文档描述, 只读元组为元组的父类型,那么下面代码示例中的 y 赋值给 x 是没有任何问题的, 因为这就是父类型赋值给子类型,是可以赋值的.
同时我问了问 GPT,以下是 GPT 的回答
在 TypeScript 中,只读元组(ReadonlyTuple)不是元组(Tuple)的父类型。
元组(Tuple)和只读元组(ReadonlyTuple)是两种不同的类型,只读元组是通过 Readonly 关键字将元组变为只读的 Utilities 类型。
具体来说:
1. 元组(Tuple)表示一个已知元素数量和类型的数组,比如:[string, number]。元组可读可写。
2. 只读元组(ReadonlyTuple)是通过 Readonly<T> 工具类型将元组变为只读的,比如:Readonly<[string, number]>。只读元组不能被修改。
3. 两者之间不存在继承关系,只读元组不是元组的子类型或父类型。
4. 但是可以将元组赋值给只读元组,因为只读元组相比元组是更加严格的类型。
所以综上所述,在 TypeScript 中,只读元组(ReadonlyTuple)和元组(Tuple)是两种不同的类型,之间不存在继承关系,只读元组不是元组的父类型或子类型。
当前菜单栏的部分不太方便,阅读到底部想切换想要的栏目还需拖回顶部。当然,是有点吹毛求疵了。不过我个人蛮重视有户体验的,仅作为建议。
类似 https://vitepress.dev/guide/what-is-vitepress ,左侧大栏目,右侧当前页的小标题(应该是当前最流行的 markdown 类布局,条理清晰)
ps:只是建议,如果改进了,万分感谢。还有搜索方案很棒。
typescript-tutorial/docs/enum.md
Line 515 in 8ad5fc6
实测这句话仅当 MyEnum 是数值 Enum 时生效,但前文例子中用的是字符串 Enum,实际是 keyof string
# 编译 src 目录的所有 .ts 文件
$ tsc src/*.ts
tsc src/.ts这个命令能用吗,我试了使用tsc src/.ts会报错:
error TS6053: File 'src/*.ts' not found.
The file is in the program because:
Root file specified for compilation
(2)set方法的参数类型,必须兼容get方法的返回值类型,否则报错。
class C {
_name = '';
get name():string {
return this._name;
}
set name(value:number) {
this._name = value; // 报错
}
}
上面示例中,get方法的返回值类型是字符串,与set方法参数类型不兼容,导致报错。
在 TypeScript 5.1 中, getter 與 setter 的參數類型不再有兼容限制
也就是說,以下的例子現在是合法的
class C {
_name = '';
get name(): string {
return this._name;
}
set name(value: number) {
this._name = String(value)
}
}
原文描述是
原型方法的装饰器首先应用,然后是静态属性和静态方法装饰器,接下来是实例属性装饰器,最后是类装饰器。
经过测试,使用 md 中的源码,增加了静态方法装饰器,使用在线的 playground,分别选择 5.0.4 / 5.2.2 运行测试
function d(str:string) {
console.log(`评估 @d(): ${str}`);
return (
value:any, context:any
) => console.log(`应用 @d(): ${str}`);
}
function log(str:string) {
console.log(str);
return str;
}
@d('类装饰器')
class T {
@d('静态属性装饰器')
static staticField = log('静态属性值');
@d('静态方法装饰器1')
static fn1(){}
@d('原型方法装饰器')
[log('计算方法名')]() {}
@d('实例属性装饰器')
instanceField = log('实例属性值');
@d('静态方法装饰器2')
static fn2(){}
}
结果输出是
[LOG]: "评估 @d(): 类装饰器"
[LOG]: "评估 @d(): 静态属性装饰器"
[LOG]: "评估 @d(): 静态方法装饰器1"
[LOG]: "评估 @d(): 原型方法装饰器"
[LOG]: "计算方法名"
[LOG]: "评估 @d(): 实例属性装饰器"
[LOG]: "评估 @d(): 静态方法装饰器2"
[LOG]: "应用 @d(): 静态方法装饰器1"
[LOG]: "应用 @d(): 静态方法装饰器2"
[LOG]: "应用 @d(): 原型方法装饰器"
[LOG]: "应用 @d(): 静态属性装饰器"
[LOG]: "应用 @d(): 实例属性装饰器"
[LOG]: "应用 @d(): 类装饰器"
[LOG]: "静态属性值"
所以在5.x的版本下,结论应该是
静态方法装饰器首先应用,然后是原型方法的装饰器和静态属性装饰器,接下来是实例属性装饰器,最后是类装饰器。
而使用4.x的版本输出结果为,也与描述不符
[LOG]: "计算方法名"
[LOG]: "静态属性值"
[LOG]: "评估 @d(): 原型方法装饰器"
[LOG]: "应用 @d(): 原型方法装饰器"
[LOG]: "评估 @d(): 实例属性装饰器"
[LOG]: "应用 @d(): 实例属性装饰器"
[LOG]: "评估 @d(): 静态属性装饰器"
[LOG]: "应用 @d(): 静态属性装饰器"
[LOG]: "评估 @d(): 静态方法装饰器1"
[LOG]: "应用 @d(): 静态方法装饰器1"
[LOG]: "评估 @d(): 静态方法装饰器2"
[LOG]: "应用 @d(): 静态方法装饰器2"
[LOG]: "评估 @d(): 类装饰器"
[LOG]: "应用 @d(): 类装饰器"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.