gpt4 book ai didi

TypeScript 仅允许参数中父对象的子项

转载 作者:搜寻专家 更新时间:2023-10-30 21:49:14 25 4
gpt4 key购买 nike

假设我有以下接口(interface)。我想从那些接口(interface)(如Actor/Film)声明objects并将它们传递到一个类( 来自)。 From 类有一个方法,Select,我只希望它们获取传递的对象 (Actor) 的子对象。我做错了吗?有没有更好的办法?这行不通,我不太清楚该怎么做。

interface ColumnString {
maxLength: number
}

type ColumnType = ColumnString | typeof Number | typeof Date

interface Column {
toString: () => String
column: ColumnType
}

interface Table {
toString: () => string
columns: { [columnName: string]: Column }
}

const Actor: Table = {
toString: () => "Actor",
columns: {
FirstName: {
toString: () => "FirstName", column: { maxLength: 50 }
},
LastName: {
toString: () => "LastName", column: { maxLength: 50 }
},
BirthDate: {
toString: () => "BirthDate", column: Date
}
}
}

const Film: Table = {
toString: () => "Film",
columns: {
FilmTitle: {
toString: () => "FilmTitle", column: { maxLength: 100 }
},
Rating: {
toString: () => "Rating", column: { maxLength: 5 }
}
}
}

// This doesn't work
type TableColumn<T extends Table> = { [P in keyof T["columns"]]: Column }

class From1<T extends Table> {
private table: T
private columns: TableColumn<T>

constructor(table: T) {
this.table = table
}

public Print() {
console.log("Table:", this.table.toString())
Object.keys(this.columns).forEach((column, idx) => {
console.log("Column", idx+":", column.toString())
})
}

// This doesn't work.
public Select(...columns: TableColumn<T>[]) {
this.columns = columns
return this
}

}

function From<T extends Table>(table: T) {
return new From1(table)
}

const A = Actor.columns
const F = Film.columns

From(Actor)
// Should fail when I pass in F.FilmTitle but be OK with
// any Actor Column
.Select(A.FirstName, F.FilmTitle)
.Print()

我尝试了很多东西,但我不确定如何去做。

提前致谢!

最佳答案

您需要将列/表的名称作为字符串文字类型进行流动。然后,您可以利用不同字符串文字类型不兼容的事实来确保您无法传递给不同表的 Select 列。

我不得不稍微改变一下类的结构,让它有一个 name 属性,还有一些额外的初始化必须在表和列上完成,所以我不得不添加一些额外的功能,但结果实际上非常有用。

用法

const Actor = table("Actor", {
FirstName: { maxLength: 50 },
LastName: { maxLength: 50 },
BirthDate: Date
});

const Film = table("Actor", {
FilmTitle: { maxLength: 50 },
Rating:{ maxLength: 50 },
});

const A = Actor.columns
const F = Film.columns

From(Actor)
// A.FirstName is ok, F.FilmTitle fails
.Select(A.FirstName, F.FilmTitle)
.Print()

实现

type ColumnType = { maxLength: number } | (new () => Date); //For testing 

interface Column<TName = string, TOwnerName = string> {
name: TName;
tableName : TOwnerName;
column: ColumnType;
toString(): string;

}

interface Table<TName, TColumns extends { [name: string]: Column }> {
name: TName;
toString(): string;
columns: TColumns
}

function table<TTableName extends string, TColumns extends { [name: string]: ColumnType }>(tableName: TTableName, columnTypes: TColumns) : Table<TTableName, { [P in keyof TColumns] : Column<P, TTableName>}> {
let columns :{ [P in keyof TColumns] : Column<P, TTableName>} = {} as any;
for(let key of Object.getOwnPropertyNames(columnTypes)) {
columns[key] = {
name: key,
toString : () => key,
column: columnTypes[key],
tableName: tableName
}
}

return {
name: tableName,
toString: () => tableName,
columns
};
}

class From1<TTableName extends string, TColumns extends { [name: string] : Column }> {
private table: Table<TTableName, TColumns>
private columns: Column<keyof TColumns, TTableName>[]

constructor(table: Table<TTableName, TColumns>) {
this.table = table
}

public Print() {
console.log("Table:", this.table.toString())
this.columns.forEach((column, idx) => {
console.log("Column", idx + ":", column.toString())
})
}
public Select<TColumnName extends keyof TColumns>(...columns: Column<TColumnName, TTableName>[]) {
this.columns = columns
return this
}

}

function From<TTableName extends string, TColumns extends { [name: string] : Column<string> }>(table: Table<TTableName, TColumns>) {
return new From1(table)
}

关于TypeScript 仅允许参数中父对象的子项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48693491/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com