Typescript泛型-如何通过提供构造函数来改进类型的类型推断

d8tt03nd  于 2023-05-08  发布在  TypeScript
关注(0)|答案(1)|浏览(204)

我用搜索和问题形式寻找建议的问题,但没有找到适合我上下文的解决方案。
最近我注意到,如果不显式地重复类型引用,Typescript就不能从提供的构造函数中检测类型。因此,对于定义为的函数:

export interface IType<T> {
  new():T;
}

function useSomeType<T>(ctr:IType<T>, properties:Partial<T>);

我必须写一些东西:

useSomeType<TypeName>(TypeName, {
  propName: 1
});

而不是

useSomeType(TypeName, {
  propName: 1
 });

否则IDE(webstorm)无法检测properties参数的T是否为SomeType,并且无法提供intellicense和建议属性名称。
我必须如何定义useSomeType的这些参数的类型,才能智能地理解properties的属性,就像示例中的propName一样?
更新:
我在Typescript Playground上得到了这个:
https://www.typescriptlang.org/play?#code/MYGwhgzhAEAqCmEAuBhcVoG8CwAoa0AlgCYBc0yAToQHYDmA3HgUoQLbykAiYS8T+aByhg6nCkmr1oAXmgAieQIC+ePLT6UAZmGDxoASVgBPAA7wAPLAB8WZtBrwA7gAoAlKVgq1uPPAAepgD2lEhENJo6eoYA8gBGAFbwwEgQAGK6SCHGdoLAlPC8lrDQAXw0xDBBiclI1i5IZpxGTVbWADTQppRBphCkAApgoYRgIG0eXniqvrgg8GFRWZTGpAbxSSnpmdmyuQT5hXxWpf7lldDVm3UNTQBK8FprJuZtnd29-UMjYxOe+wRoPMwgUkP85I4nNBGuYHlp3AJAdBQQBXSg0aAbWoAOkgEEIdBoLlB7x6fTc0EgcER0BmMx8eCW2WxhyKLgQyDQeM6OEEwggonE8g5SHk0zcQA

class TestClass {
  id: string;
  time:Date;
  message: string = "";
}

interface IType<T> {
  new():T;
}

export interface IObjectsFactory {
  create<T extends object>(type:IType<T>, props:Partial<T>):T;
}

let factory:IObjectsFactory = {
  create<T extends object>(typeRef:IType<T>, props:Partial<T>):T {
    let ret:T = new typeRef();
    return Object.assign(ret, props) as T;
  }
}


factory.create(TestClass, {
  message: "Test"
// the properties are listed by playground
});

问题
如果这些是不同的文件(和包),这对我不起作用,比如:

  • IType<T>定义在一个包中,确切地说是@sakartvelosoft/types-metadata
  • 接口在一个文件中声明,实现在另一个文件中,测试在第三个文件中。所有这些都在莫诺雷波的内部。

我的声明:

import {CallableIdFactory} from "@sakartvelosoft/id-generation";
import {IType} from "@sakartvelosoft/types-metadata";


export interface EventMetadata {
    type: string;
    id: string;
    timestamp: Date;
    source:string;
    targets?: string[];

    scopeOrModuleId?: string;

    preferredChannel?:string;

}

export interface EventDetails<T> extends EventMetadata {
    data: T;
}

export interface EventCreationOptions {
    source?: string;
    targets?:string[];

    scopeOrModuleId?: string;

    preferredChannel?:string;
}

export interface IEventsFactoryOptions {
    eventIdFactory?:CallableIdFactory;
    source?:string;
    targets?:string[];
    targetsCleanup?:(eventType: string, source:string, targets:string[]) => string[];
}

export interface IEventFactoryEntry<T extends object> {
    createEvent(data:Partial<T>, options?:EventCreationOptions):EventDetails<T>;
    rebuildEvent(eventMetadata:EventMetadata, data:object):EventDetails<T>;
}
export interface IEventsFactory {
    registerEventsType<T extends object>(eventType:IType<T>, typeAlias?:string):void;
    forEvent<T extends object>(eventType: IType<T>):IEventFactoryEntry<T>;
    forEventByAlias<T extends object>(eventTypeAlias:string):IEventFactoryEntry<T>;

    createEvent<T>(typeDef:IType<T>, data:Partial<T>, options?:EventCreationOptions):EventDetails<T>;
    rebuildEvent(eventMetadata:EventMetadata, data:object):EventDetails<T>;

}

测试:

import {describe} from "mocha";
import {createEventsFactory} from "../src";
import {createTypesRegistry} from "@sakartvelosoft/types-metadata";
import {expect} from "chai";

describe('Test events construction and rebuilding', () => {
    class TestEvent {
        message: string;
    }
    it('Construct event', () => {
        const eventFactory = createEventsFactory(createTypesRegistry(), { source: 'test' });
        eventFactory.registerEventsType(TestEvent, 'test-event');
        const newEvent = eventFactory.createEvent(TestEvent,  {
            message: "Demo"

        });
        expect(newEvent.data).haveOwnProperty('test');
        expect(newEvent.data).instanceof(TestEvent);
        expect(newEvent.data.test).eql('Demo');
    })
})

更新2:
(几乎)提到的代码似乎在TSFiddle中按预期工作(TestEvent的属性被识别/理解/列出),但在WebStorm项目中却不是,如果我理解正确的话,这是非常奇怪的,Webstorm不能正确地推断类型,而TSFiddle可以。
TSFiddle链接:https://stackblitz.com/edit/tsfiddle-quxumi?file=src%2Fapp%2Finterfaces.ts,src%2Fapp%2Ftest-code.ts,src%2Fapp%2Fstubs.ts
更新3
正如我所看到的,由于TSFiddle没有显式的tsconfig.json文件,并且它们使用了一些内置的“配置”,我在我的项目的根目录下提供了tsconfig,在那里我经历了以下情况:

{
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2021",
    "lib": ["ES2021"],
    "sourceMap": true,
    "outDir": "./dist",
    "declaration": true
  },
  "include": ["./src/**/*.ts", "./tests/**/*.ts"],
    "compileOnSave": true,
    "exclude": [
    "node_modules"
  ]
}

.eslintrc.js

/* eslint-env node */
module.exports = {
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  root: true,
};

package.json中的dev-dependencies列表:

{
"devDependencies": {
    "@types/chai": "^4.3.5",
    "@types/mocha": "^10.0.1",
    "@types/node": "^18.16.3",
    "@typescript-eslint/eslint-plugin": "^5.59.2",
    "@typescript-eslint/parser": "^5.59.2",
    "chai": "^4.3.7",
    "eslint": "^8.39.0",
    "mocha": "^10.2.0",
    "ts-mocha": "^10.0.0",
    "typescript": "^5.0.4"
  }
}

解决方案
在进一步研究问题原因和影响配置和问题之后,我发现从TypeScript版本(如最新的5.0.2)降级到旧版本(如4.8.4)似乎可以解决问题。尽管如此,希望它将被修复与5.0.2类型脚本版本,我添加了一个相关的错误在他们的(网络 Storm )跟踪器。
将关闭此问题,因为有可用的解决方法。

xwbd5t1u

xwbd5t1u1#

解决方案
在进一步研究问题原因和影响配置和问题之后,我发现从TypeScript版本(如最新的5.0.2)降级到旧版本(如4.8.4)似乎可以解决问题。尽管如此,希望它将被修复与5.0.2 typescript 版本,我添加了一个相关的错误在他们的(网络 Storm )跟踪。
将关闭此问题,因为有可用的解决方法。

相关问题