青训营上课笔记
四.TypeScript
TypeScript是一种由微软开发的开源编程语言,它是JavaScript的超集,添加了静态类型检查和其他一些语言特性。在WEB开发中,TypeScript可以帮助开发者编写更健壮、可维护和可扩展的代码。
1.基本类型
// TypeScript支持JavaScript的基本类型,如number、string、boolean、null、undefined和object等。在声明变量时,可以明确指定变量的类型。
let age: number = 25;
let name: string = "John";
let isStudent: boolean = true;
let person: object = {age: 25, name: "John"};
2.接口
// TypeScript中的接口可以用来定义一个对象的结构。它们可以包含属性、方法和可选属性。
interface Person{
age: number;
name: string;
sayHello:()=>{
soncole.log("Hello!")
},
address: "123 ABC Street"
};
3.类
// TypeScript支持面向对象编程的概念,可以使用类来创建对象。类可以有属性、方法和构造函数。
class Person{
age: number;
name: string;
constructor(age:number, name:string){
this.age = age;
this.name = name;
}
sayHello(){
console.log("Hello!");
}
}
let person = new Person(25, "John");
person.sayHello();
4.模块化
// TypeScript支持模块化开发,可以使用import和export关键字导入和导出模块。
// math.ts
export function add(a: number, b: number): number{
return a + b;
}
export function substract(a: number, b: number): number{
return a - b;
}
// math.ts
import{add, substract}from"./math";
console.log(add(2, 3)); // 输出5
console.log(substract(5, 2)); // 输出3
5.泛型
// TypeScript支持泛型,可以创建可重用的、类型安全的代码。
function reverse<T>(array: T[]):T[]{
return array.reverse();
}
let numbers = [1, 2, 3, 4, 5];
let reversedNumbers = reverse(numbers);
console.log(reversedNumbers); // 输出[5, 4, 3, 2, 1]
let strings = ["apple", "banana", "cherry"];
let reversedStrings = reverse(strings);
console.log(reversedStrings); // 输出["cherry", "banana", "apple"]
6.类型注解和类型推断
//TypeScript允许开发者明确指定变量的类型,这被称为类型注解。同时,TypeScript还可以根据上下文自动推断变量的类型,这被称为类型推断。
let age: number = 25;
// 在这个例子中,我们明确指定了age变量的类型为number。
let name = "John";
// 在这个例子中,TypeScript可以根据赋值表达式自动推断出name变量的类型为string。
7.类型别名和联合类型
// TypeScript支持使用type关键字定义类型别名,可以将复杂的类型命名为一个简单的别名。
type Name = string;
type Age = number;
let name: Name = "John";
let age: Age = 25;
// 在这个例子中,Name和Age被定义为类型别名,它们分别表示string和number。
// TypeScript还支持联合类型,可以表示一个值可以具有多个类型中的一个。
type NumberOrString = number | string;
let value: NumberOrString = 123; // 或者 "abc"
// 在这个例子中,NumberOrString表示一个值可以是number或string类型。
8.接口的继承
// TypeScript中的接口可以继承其他接口,通过extends关键字实现。这样可以创建更具体的接口定义。例如:
interface Animal {
eat: () => void;
}
interface Cat extends Animal {
meow: () => void;
}
let cat: Cat = {
eat: () => {
console.log("Cat is eating.");
},
meow: () => {
console.log("Meow!");
}
};
// 在这个例子中,Cat接口继承了Animal接口,所以cat对象需要实现eat和meow两个方法。
9.类的继承
// TypeScript支持类的继承,可以通过extends关键字创建一个类继承另一个类。
class Animal {
eat() {
console.log("Animal is eating.");
}
}
class Cat extends Animal {
meow() {
console.log("Meow!");
}
}
let cat = new Cat();
cat.eat(); // 输出:Animal is eating.
cat.meow(); // 输出:Meow!
// 在这个例子中,Cat类继承了Animal类的属性和方法,所以cat对象可以调用eat和meow方法。
10.类型断言
// TypeScript中的类型断言用于告诉编译器某个值的具体类型。
// 有两种方式可以进行类型断言:
a.尖括号语法 <类型>:例如,(variable as string)
b.关键字:例如,(variable as string)
// 类型断言可以在需要明确指定类型的情况下使用,比如当你知道一个更具体的类型会被赋值给一个变量。
let value: any = "Hello TypeScript!";
let length: number = (<string>value).length;
// 在上面的例子中,我们将value变量的类型断言为string,然后使用length属性获取字符串的长度。
11.可选属性和只读属性
// TypeScript的接口和类中可以定义可选属性和只读属性。可选属性用于表示一个属性不是必须的,而只读属性可以在创建后不能被更改。
interface Person {
name: string;
age?: number; // 可选属性
}
let person1: Person = { name: "John" };
let person2: Person = { name: "Tom", age: 25 };
class Car {
readonly brand: string; // 只读属性
constructor(brand: string) {
this.brand = brand;
}
}
let car = new Car("Toyota");
console.log(car.brand); // 输出:Toyota
// car.brand = "Honda"; // 错误!只读属性不能被重新赋值
// 在上面的例子中,`age`属性是可选的,可以不提供。而`brand`属性是只读的,一旦被赋值后不能再次修改。
12.命名空间和模块
// TypeScript中的命名空间(namespace)和模块(module)用于组织和管理代码。
// 命名空间可以将相关的代码组织在一起,避免命名冲突。
// 模块则是一种更通用的组织代码的方式,可以用来划分功能模块,并且可以使用`import`和`export`语法导入和导出模块。
//命名空间的例子:
namespace Math {
export function add(a: number, b: number): number {
return a + b;
}
}
console.log(Math.add(2, 3)); // 输出:5
//模块的例子:
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export function subtract(a: number, b: number): number {
return a - b;
}
// main.ts
import { add, subtract } from "./math";
console.log(add(2, 3)); // 输出:5
console.log(subtract(5, 2)); // 输出:3
// 在上面的例子中,`math.ts`文件定义了`add`和`subtract`函数,并通过`export`关键字导出。然后在`main.ts`文件中使用`import`语法导入这两个函数。
13.结合HTML与CSS
a.类型安全的DOM操作
// TypeScript可以帮助我们在DOM操作时实现类型安全。
// 通过使用TypeScript的类型推断和类型注解功能,我们可以明确指定DOM元素的类型,以及相应的属性和方法。
const button = document.querySelector("#myButton") as HTMLButtonElement;
button.addEventListener("click", () => {
button.disabled = true;
});
// 在这个例子中,我们使用`querySelector`方法选择一个按钮元素,并将其断言为`HTMLButtonElement`类型。这样就可以确保我们可以访问和设置按钮的属性和方法,例如将按钮禁用。
b.使用接口定义组件的属性和状态
// TypeScript的接口可以用于定义组件的属性和状态的结构。
// 这样可以提供类型检查和自动补全的好处。
interface ButtonProps {
text: string;
disabled?: boolean;
onClick: () => void;
}
class Button {
private props: ButtonProps;
constructor(props: ButtonProps) {
this.props = props;
}
render() {
const button = document.createElement("button");
button.innerText = this.props.text;
button.disabled = this.props.disabled || false;
button.addEventListener("click", this.props.onClick);
return button;
}
}
const button = new Button({
text: "Click me",
onClick: () => {
console.log("Button clicked");
}
});
document.body.appendChild(button.render());
// 在这个例子中,我们使用`ButtonProps`接口定义了按钮组件的属性结构。
// 然后我们创建了一个`Button`类,并使用`ButtonProps`指定了构造函数的参数类型和渲染方法的返回类型。
// 这样可以确保我们在使用按钮组件时传递了正确的属性,并且属性的类型是符合预期的。
c.结合模块化的开发
// TypeScript的模块化功能可以帮助我们将代码组织成可重用的模块,并通过`import`和`export`语法进行导入和导出。
// 结合HTML和CSS,我们可以将相关的代码、样式和模板放在同一个模块中。
import "./button.css";
interface ButtonProps {
// 属性定义...
}
class Button {
// 类定义...
}
export default Button;
// 在这个例子中,我们使用`import`语法导入了一个名为`button.css`的样式文件。然后我们定义了一个按钮组件,并在需要使用该组件的地方通过`import`语法进行导入。
d.类型化框架和库的使用
// TypeScript可以与许多流行的前端框架和库进行无缝集成,从而提供更好的类型支持和开发体验。
// 例如,Angular是一个使用TypeScript编写的强大的前端框架,它提供了丰富的类型定义和类型检查。
// Vue.js也有一个专门为TypeScript设计的官方插件,可以使Vue.js应用程序具备类型安全和编译时检查的优势。
// 使用TypeScript编写的Angular组件
@Component({
selector: 'app-button',
template: '<button (click)="onClick()">{{ text }}</button>'
})
export class ButtonComponent {
@Input() text: string;
@Output() clicked: EventEmitter<void> = new EventEmitter<void>();
onClick(): void {
this.clicked.emit();
}
}
// 使用TypeScript编写的Vue.js组件
@Component
export default class ButtonComponent extends Vue {
@Prop() text!: string;
onClick(): void {
this.$emit('clicked');
}
}
e.类型化的HTTP请求
// 在前端开发中,与服务器进行通信是很常见的任务,使用TypeScript可以使HTTP请求更具类型安全性。
// 例如,可以使用`fetch`函数结合`async/await`语法来发起异步HTTP请求。
interface Todo {
id: number;
title: string;
completed: boolean;
}
async function fetchTodo(): Promise<Todo[]> {
const response = await fetch('https://api.example.com/todos');
const data = await response.json();
return data as Todo[];
}
const todos = await fetchTodo();
console.log(todos);
// 在这个示例中,我们定义了一个`Todo`接口来表示待办事项的数据结构。
// 然后,使用`fetch`函数发起HTTP请求,并使用`await`等待数据的返回。
// 最后,我们将返回的数据转换为`Todo[]`类型。
f.类型定义文件(Type Declaration Files)
// 在与第三方JavaScript库或框架集成时,可以使用类型定义文件(.d.ts文件)来描述这些库的类型信息,从而为TypeScript提供类型检查和代码提示。
// 类型定义文件提供了函数、类、接口和模块的声明,以及导出的类型定义。
// 例如,假设我们使用了一个第三方库`lodash`,我们可以创建一个`lodash.d.ts`文件来描述它的类型信息:
// lodash.d.ts
declare module 'lodash' {
export function chunk(array: any[], size?: number): any[][];
export function debounce(func: Function, wait?: number): Function;
// 其他函数和类型声明...
}
// 在这个例子中,我们使用`declare module`语法来声明我们正在描述的模块(`'lodash'`)。然后我们通过`export`语法来导出函数和类型的声明。这样,当我们在TypeScript中导入`lodash`时,就可以进行类型检查和代码提示。
g.类型别名(Type Aliases)
// 类型别名可以用来为类型创建一个新的名称,使代码更加可读和可维护。我们可以使用`type`关键字来定义类型别名。
type Person = {
name: string;
age: number;
};
type Point = [number, number];
// 在这个例子中,我们创建了两个类型别名。`Person`是一个对象类型的别名,它具有`name`和`age`属性。`Point`是一个元组类型的别名,它表示具有两个数字的数组。
h.keyof操作符和索引类型查询
// TypeScript支持`keyof`操作符和索引类型查询,这让我们可以通过类型变量来访问对象的属性。使用这种方式可以在编译时获得属性的名称,从而避免运行时的错误。
type Person = {
name: string;
age: number;
};
function getProperty(obj: Person, key: keyof Person) {
return obj[key];
}
const person: Person = { name: 'John', age: 25 };
const name = getProperty(person, 'name');
console.log(name); // 输出:John
// 在这个例子中,我们使用`keyof Person`来获得`Person`对象的所有属性名称。然后我们编写了一个函数`getProperty`,它接收一个对象和一个属性名称,然后返回该属性的值。