重要更新-2019-3-22:InstanceType

预定义的有条件类型 TypeScript 2.8在lib.d.ts里增加了一些预定义的有条件类型: Exclude — 从T中剔除可以赋值给U的类型。 Extract — 提取T中可以赋值给U的类型。 NonNullable — 从T中剔除null和undefined。 ReturnType — 获取函数返回值类型。 InstanceType — 获取构造函数类型的实例类型。

因此可以改为:

  1. const load_res = <T extends typeof cc.Asset>(path: string, type: T): Promise<InstanceType<T>> => {
  2. return new Promise(res => {
  3. cc.loader.loadRes(path, type, (err, resource) => {
  4. if (err) {
  5. res(null)
  6. } else {
  7. res(resource)
  8. }
  9. })
  10. })
  11. }

在脚本编写中,cc.load.loadRes()方法的参数类型描述是一个比较复杂的部分。简化描述,相当于传入一个类型X的类型,返回一个类型X的值。

在ts中,有typeof关键字可以用来描述类型,例如:

let a: typeof cc.Prefab = cc.Prefab

在这一行代码中,cc.Prefab即可以作为类型,也可以作为值,还是很方便的。

于是针对cc.load.loadRes()方法,可以写成:

const load_res = <T extends cc.Asset>(path: string, type: new () => T): Promise<T> => {
    return new Promise(res => {
        cc.loader.loadRes(path, <any>type, () => { }, (err, resource) => {
            if (err) {
                res(null)
            } else {
                res(resource)
            }
        })
    })
}

这样,可以实现,传入泛型T返回泛型T的类型描述。

其中:

  1. new()=>T相当于typeof T,但是在泛型中不可直接使用,要采用构造函数的方式。参考https://jkchao.github.io/typescript-book-chinese/faqs/generics.html#为什么不要在泛型函数中写-typeof-t、new-t-或者-instanceof-t?
  2. <any>是用来强制转换的,如果不加,type参数会类型报错,具体原因可能与creator.d.ts中的定义有关,还不清楚。