TypeScript发疯实录

134 阅读1分钟

一、keyof解决访问对象或者数组key,报错不是有效属性的问题

首先,这是一个看似非常正常的代码:

for (const param in params) {
    if (params[param]) {
      path += `&${param}=${params[param as keyof AlartRulemodel]}`
    }
}

image.png

嗯?报错了,看看是什么:不要用for in循环,不然引入的运行时库可能太重量级。

OK,那我Object.keys + forEach丝滑小连招:

Object.keys(params).forEach((param) => {
    if (params[param]) {
      path += `&${param}=${params[param]}`
    }
  })

image.png

嗯?报错了,看看是什么:觉得 param 可能不是 params 有效属性! 好冤啊! 明明是从param出来的!

那那那,我加一个判断?这下ts该不会阻拦我访问params[param]了吧!

Object.keys(params).forEach((param) => {
    if (params.hasOwnProperty(param) && params[param]) {
      path += `&${param}=${params[param]}`
    }
})

image.png

嗯?报错了,看看是什么:哦哦,hasOwnProperty 方法是继承自 Object.prototype 的,可能会导致潜在的问题。应该是TS静态分析工具报错。再改改!

fine,我改成in

image.png

嗯?报错了,看看是什么:怎么还是觉得 param 不是 params 有效属性!

那类型断言?

Object.keys(params).forEach((param) => {
    if (params[param as keyof AlartRulemodel]) {
      path += `&${param}=${params[param as keyof AlartRulemodel]}`
    }
  })

二、进行类型定义

业务场景

如果要将下面一个数组filterOptions的键值依次填到对象form对应的属性中:

image.png

使用以下方法:

image.png

怎么解决这三个隐式any呢?

  • 对于第一个,设置filreOptions的参数类型,是一个对象数组,我们定义对象的类型即可。它固定有两个属性,直接使用type
type FilterOption = {
        schemaKey: string,
        rightModelValue: string
      }

image.png

这时候可以看出,第二个隐式any由于能自动推断,错误已经消失,当然,也可以为其进行显式指定。

  • 对于第三个, 访问数组属性,被指出可能不是有效属性,同一,进行类型断言
type Form = Record<
      'alertName' | 'level' | 'ruleGroupId' | 'appName' | 'commander' |
      'oncallGroup' | 'createdBy' | 'title' | 'ruleTypeId' | 'isAsuraRule',
      string
    >

(这时候form的定义也可以用Form进行显示推断了)

const form: Form = reactive({
      alertName: '',
      level: '',
      ruleGroupId: '',
      appName: '',
      commander: '',
      oncallGroup: '',
      createdBy: '',
      title: '',
      ruleTypeId: '',
      isAsuraRule: ''
    })

最终可执行代码:

image.png

const searchAlartRule = async (filterOptions: FilterOption[]) => {
      filterOptions.forEach((option) => {
        form[option.schemaKey as keyof Form] = option.rightModelValue
      })
      await getRuleList()
      clearForm()
    }

Record

Record 的作用是定义一个对象类型,该对象类型包含一组属性,这些属性的名称由 K 类型确定,而属性的值类型由 T 类型确定。

type StudentRecord = Record<string, number>

这样,就定义好了键为string类型,值为numer类型的对象。

const students: StudentRecord = {
  "Alice": 18,
  "Bob": 19,
  "Charlie": 20,
}

当然,也可以用 | 来限制键值:

type Form = Record<
      'alertName' | 'level' | 'ruleGroupId' | 'appName' | 'commander' |
      'oncallGroup' | 'createdBy' | 'title' | 'ruleTypeId' | 'isAsuraRule',
      string
    >

Partial 和 ?控制可选

- Partial:每一个属性都是可选的。

// 使用 Partial 类型来定义初始类型
type Form = Partial<{
  alertName: string;
  level: string;
  ruleGroupId: string;
  appName: string;
  commander: string;
  oncallGroup: string;
  createdBy: string;
  title: string;
  ruleTypeId: string;
  isAsuraRule: string;
}>;

这里的<>指定的是类型参数。<>还可以用于函数泛型

function identity<T>(arg: T): T {
  return arg;
}

- ?:控制单个属性可选。

type Form = {
    alertName?: string
    level: string
}