怎么灵活运用TypeScript的keyof、type

// 1 怎样才能知道 s 是 _t 的其中一个,而不是任意的 string
type _t = "1" | "2";
function f(s: _t | string) {}

// 2 (已解)
type point = [number, number];
type polygon = [point, point, point, point];// 4个或4个以上,有没有灵活限制类型长度的方法

// 3 (已解)在constructor中执行了b,相当于初始化直接赋值了a=1,为什么ts说b没有初始化
class Demo_1 {
  a: number;
  constructor() {
    this.b();
  }
  b() {
    this.a = 1;
  }
}

// 4 ts的索引类型
const p = {
  name: "xxx",
  age: 18
};
Object.keys(p).forEach((key) => {
  console.log(p[key]);// 这样取值报错,不是索引类型应该怎么解决
});

求解惑,或者换种思路解决相同需求

阅读 2.1k
4 个回答

第一个问题,我不是很确定你的需求。如果是要根据参数类型规定返回类型之类的,直接多写几个同名定义就可以了。像下面这样,对于参数类型符合 Temp 的 TS 会要求返回类型为 true,对不符合的字符串则要求 false

type Temp = '1' | '2';
function f(s: Temp): true;
function f(s: string): false;
function f(s: string): boolean {
  return (s === '1' || s === '2');
}

参见 Function Overloads

第二个问题已经有了满意的答案。

第三个问题还没有结束,题主问的 “为什么” 还没人回答。TS 文档在 Classes 中的 --strictPropertyInitialization 选项 里给出的解答原文是

TypeScript does not analyze methods you invoke from the constructor to detect initializations, because a derived class might override those methods and fail to initialize the members.

If you intend to definitely initialize a field through means other than the constructor (for example, maybe an external library is filling in part of your class for you), you can use the definite assignment assertion operator, !

前段大意是 因为子类可能重写掉这些方法,所以 TS 不会去分析构造函数中调用的方法初始化的属性。后段大意就是在你能确保该属性被初始化的情况下使用 ! 跳过检查。

为了避开提到的可能被重写的问题,建议在该方法上使用 private 关键字或其他等效方法(如果有)避免重写。不过目前 TS 并不会因此分析该方法内初始化的属性(TS 没有要特别解决的意思但已经标为设计缺陷),依然需要 !

第四个问题可见 Why doesn't Object.keys return a keyof type in TypeScript? - Stack Overflow,原因和变通方案都有回答。变通方案一般是用 as 自己标记类型。

(Object.keys(p) as Array<keyof typeof p>).forEach((key) => {
  console.log(p[key]);
});
// 2 
type point = [number, number];
// 4个或4个以上,有没有灵活限制类型长度的方法
type polygon = [...point[], point, point, point,point];
const s: polygon = [[1, 1], [1,1], [1,1], [1,1]]

// 3 在constructor中执行了b,相当于初始化直接赋值了a=1,为什么ts说b没有初始化
class Demo_1 {
  a!: number;
  constructor() {
    this.b();
  }
  b() {
    this.a = 1;
  }
}

第一个,不太确定,为什么要分出是I而非K,即使I和K是不一样的类型,应该去使用判断去区分,去决定怎么处理逻辑,而且一般I和K类型应该一样吧。

第二个:

type point = Array<number>;

type polygon = Array<point>;

第三个:

class Demo_1 {
  a!: number;
  constructor() {
    this.b();
  }
  b() {
    this.a = 1;
  }
}

针对第一题:怎么着,ts是js的超集,就可以把逻辑放在类型系统只上了吗?

二三题已经解了

针对第四题:

const p: {[key: string]: any} = {
  name: "xxx",
  age: 18
};
Object.keys(p).forEach((key) => {
  console.log(p[key]);
});

这是一种方式

另外,你不知道数组也能Object.keys吧

let a:number[] = [1,2,3]

Object.keys(a).forEach(i => {
  console.log(a[Number(i)])
})

甚至还可以再震撼一点

const p: {[key: string]: any} = {
  name: "xxx",
  age: 18,
  4: 12
};
Object.keys(p).forEach((key) => {
  
  console.log(p[key]);

  if(key === '4') {
    console.log(">>>", p[Number(key)])
  }
});

我觉得你应该知道你第四个问题的原因了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题