是否可以在Typescript中从父函数调用的函数中使用类型?

2exbekwf  于 2023-01-06  发布在  TypeScript
关注(0)|答案(3)|浏览(112)

我想在另一个函数中调用一个函数,并在调用子函数时使用其类型参数作为“默认”类型。
在 typescript 中可以吗?

// Parent interface
interface IParent {
    id: number;
    name: string;
}

// Child interface with foreign key
interface IChild {
    id: number;
    name: string;
    ParentId: number;
}

// Parent function declaration:
function select<T>(query: {
    select: string,
    join: string,
}) {
    return `${query.select} ${query.join}`;
}

// Child function declaration (F type is optional):
function buildJoin<T, F = Record<any, any>>(foreignKey: keyof T, otherColumn: keyof F): string {
    return 'JOIN f on t.foreignKey = f.otherColumn';
}

// Strong typing:
select<IParent>({
    select: 'select * from Parent',
    join: buildJoin<IChild, IParent>('ParentId', 'id'), // explicitly typed "ParentType"
});

// Requested behaviour:
select<IParent>({
    select: 'select * from Parent',
    join: buildJoin<IChild>('ParentId', 'id'), // if 2nd type parameter omitted it should be taken from parent function
});

typescript Playground链接

fcg9iug3

fcg9iug31#

你试图根据buildJoin的调用位置来推断它的类型参数,但你做不到,所以从这个意义上说,你的问题的答案是“否”。
作为一种替代方法,你可以写一个fluent interface,其中selectjoin方法返回一个对象,然后继承类型参数的值。下面是一个粗略的例子(不打算成为一个真正健壮的实现[尽管它确实适用于这个有限的例子],只是一个例子):

// Parent interface
interface IParent {
    id: number;
    name: string;
}

// Child interface with foreign key
interface IChild {
    id: number;
    name: string;
    ParentId: number;
}

// Parent function declaration:
function select<ParentType>(select: string) {
    return {
        query: select,
        join<ChildType>(foreignKey: keyof ChildType, otherColumn: keyof ParentType) {
            this.query += "\nJOIN f on t.foreignKey = f.otherColumn";
            return this;
        },
        build() {
            return this.query;
        },
    };
}

// Strong typing:
const sql = select<IParent>("select * from Parent")
    .join<IChild>("ParentId", "id")
    .build();

Playground示例

ctehm74n

ctehm74n2#

还有另一种选择,依赖于标记的原语类型、currying和函数组合。

const select = <Parent>(select: string) =>
    select as string & { _parent: Parent };

const join = <Child>(foreignKey: keyof Child) => <Parent>(otherColumn: keyof Parent) =>
    (select: string & { _parent: Parent }) =>
        `${select}\nJOIN f on t.foreignKey = f.otherColumn`;

你可以这样使用它

import { pipe } from 'fp-ts/lib/function'

const ok1 = pipe(
    select <IParent>("select * from Parent"),
    join <IChild>("ParentId") ("id")
)

const ok2 = pipe(
    select <IParent>("select * from Parent"),
    join <IChild>("ParentId") <IParent>("id")
)

复陆

628mspwn

628mspwn3#

是的,这是可能的。通过调用constructor方法中的super()方法,我们调用了父代的constructor方法,并获得了对父代的属性和方法的访问。继承对于代码的可重用性很有用:在创建新类时重用现有类的属性和方法。

相关问题