[项目地址] (github.com/type-challe…
extends 关键字
继承作用此处不做讨论
extends官方示例
//BasicAddress
interface BasicAddress {
name?: string;
street: string;
city: string;
country: string;
postalCode: string;
}
此时如果需要一个新的
interface并且与BasicAddress建立联系
// AddressWithUnit
interface AddressWithUnit {
name?: string;
unit: string;
street: string;
city: string;
country: string;
postalCode: string;
}
这样可以达成目的,但是必须重复声明所有从BasicAddress的属性类型,事实上我们可以拓展BasicAddress的属性,甚至可以顺便在其中增加新的属性
interface AddressWithUnit extends BasicAddress{
unit:string;
}
```
当然interface也支持同时多个拓展
```typescript
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
interface ColorfulCircle extends Colorful, Circle {}
const cc: ColorfulCircle = {
color: "red",
radius: 42,
};
```
### 泛型约束
泛型定义常常包括一些限制,如泛型`A`必须包括类型`b`,那么就可以使用`extends`关键字进行限制
```typescript
//error
//Type '{ latitude: number; }' is not assignable to type '{ longitude: //number; }'.
// Object literal may only specify known properties, and 'latitude' does not exist in type '{ longitude: number; }'.
type Test<T extends {longitude : number}>={
[P : string] :T;
}
const temp:Test<{longitude : number}>={
location:{
latitude:12345
}
}
//pass
type Test<T extends {longitude : number}>={
[P : string] :T;
}
const temp:Test<{longitude : number}>={
location:{
longitude:12345
}
}
```
### 条件类型
> [ts类型体操](https://www.typescriptlang.org/play?#code/PQKgUABBAsDMEFoIFEAeBjANgVwCYFNJEETSiAjATwgC0ALfRgOwHMIAKAAQC8HmWAlBADE+AIYBnasPLYAlpgAuCOUyJFhmiAEVs+CYrkB7NVCIBJALYAHTPkv4miiIoYRZC5apQYcBADwAKgA0EACqAHxEET5YePgQAGYATkaWEIEudEYSCYqU1vpZYs5iyQmSEnIsTGLkdi5G4epQMQBqcvgA7hAmEADicooAEtjkAFwQdIqK1hLjwMCKEuh0AHQAVhJrRskswHBgIMBgp6AQAPpX1zfXEACaRtjJEADCRgQQw-jll7f-Fwgx1O+UKEAAspQ0HEAiFwjEALwQMRMSinMDnAH-DL6ZyvSRFLG3IEnOQ2XbOUEJADeKAAjtgxJhQmhCuhnABfJKpdIAck4VIQqyZdlY+mA2EMmAkvJBBQS6AJEggSIA2kRWfh2f5kAymf5IdC-Ph-LyxLyIAAfCC88gW6289C80Jm3kRFm+eKm81Wm1232O50280RUPBDWoNmKHV6zAGqGegKugP+h1Ol0+h1292xY3e+1+guBjNF7NhiNRmOMuOGxMmgzJVRsa1MbCWcg-X3sdhCBExABuRjkuAEoQAYtgmOzjEwc0avQ2m77W+3O9bu72B0OR+PJ9OTKH3WAALrojEgP5Eq4QCfJVydgDKinwc0vV5J5+iEAfdDKCUoTwvBIRg4IYJjzFMMxzAsSwrOsWw7HsBywMAKISF0Pxfh03QQMBoEzhB0yzPMizLKsmzbLs+xwMAeGSgRX7grsCSvL+mCiiw+iTER0GkXBFGISwRwnGAQA)
```typescript
//type challenge
/*
43 - Exclude
-------
by Zheeeng (@zheeeng) #easy #built-in
### Question
Implement the built-in Exclude<T, U>
> Exclude from T those types that are assignable to U
> View on GitHub: https://tsch.js.org/43
*/
/* _____________ Your Code Here _____________ */
type MyExclude<T, U> = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a'>, Exclude<'a' | 'b' | 'c', 'a'>>>,
Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a' | 'b'>, Exclude<'a' | 'b' | 'c', 'a' | 'b'>>>,
Expect<Equal<MyExclude<string | number | (() => void), Function>, Exclude<string | number | (() => void), Function>>>,
]
/* _____________ Further Steps _____________ */
/*
> Share your solutions: https://tsch.js.org/43/answer
> View solutions: https://tsch.js.org/43/solutions
> More Challenges: https://tsch.js.org
*/
```
> ```typescript
> type MyExclude<T, U> = T extends U ? never : T;
> ```
此时`extends`用于==判定类型T是否可以分配给类型U==,而不能理解为类型T是类型U的一个子集
```typescript
//no error
type MyExclude<T, U> = T extends U ? never : T;
interface AA{
prop1:number;
}
interface BB{
prop1:number;
prop2:number;
}
let temp:MyExclude<AA,BB>;
```
特别需要注意`never`类型(never是一切类型的子类型)
```typescript
type MyExclude<T, U> = T extends U ? never : T;
interface AA{
prop1:number;
}
interface BB{
prop1:number;
prop2:number;
}
let temp:MyExclude<never,BB>;
```
## `keyof`关键字
`keyof`关键字通常用来描述对象类型,它会返回对应对象的数字或者字符串的`key`:
+ ```typescript
type Point = { x: number; y: number };
type P = keyof Point;
//type p = "x" | "y"
```
+ ```typescript
type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish;
//type A=number;
```
+ ```typescript
type Mapish = { [k: string]: boolean };
type M = keyof Mapish;
//type M= number | string
```
由于JS的原因,对象的key通常会被强制转换成`string`类型,因此上述M类型通常会被转换成number 或者 string类型
## `in`关键字
`in`关键字通常用来判断一个复合类型中是否存在左值表示的类型。类比JS中的`in`关键字(通常用来判断一个对象中是否存在某一个属性),TS中in关键字主要作用也是来缩小一个联合类型的范围的:
```typescript
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
return animal.swim();
//animal : fish
}
return animal.fly();
//animal : bird
}
```
对于`in`关键字,需要特别注意可选类型,官网给了一个例子
> *To reiterate optional properties will exist in both sides for narrowing, for example a human could both swim and fly (with the right equipment) and thus should show up in both sides of the `in` check:*
>
> 大意大概是,一个人本身是不会像鱼一样游泳或者像鸟一样飞行的,但是携带正确的装备就可以办到,因此游泳和飞行对人类来说就是一个可选类型,因此,对于可选类型,会出现在检查的两侧=> `"swim" in animal`✅ `"swim" not in animal` ❎
```typescript
type Fish = { swim: () => void };
type Bird = { fly: () => void };
type Human = { swim?: () => void; fly?: () => void };
function move(animal: Fish | Bird | Human) {
if ("swim" in animal) {
animal;
//(parameter) animal: Fish | Human
} else {
animal;
//(parameter) animal: Bird | Human
}
}
```
## `[]`语法
`[]`语法通常用来描述数组或者对象
例如:
```typescript
interface NumberArray {
[index: number]: number; //只要 index 的类型是 number,那么值的类型必须是 number。
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];//true
interface mp {
[index: string]: number; //只要 index 的类型是 string,那么值的类型必须是 number。
}
let fakemap: mp = {//true
"haha":1,
"heihei":2,
"xixi":3
}
```