I have a strange case of intermittent type evaluation. In the code below, when I start typing, the suggestion/autocomplete indicates that it is typed, and suggests correct props etc. However, once I have finished it and added a value, the type check is gone, and it won’t show an error if the property is invalid.
async function go() {
const orm = new Orm()
const results = await orm.query({
table: "tasks",
limit: 23, //<-- try deleting this property and retyping with typo, e.g.: `limitt: 23`.
fields: [
"id",
"description",
{ name: "taskType", alias: "type", fields: ["id", "name"] },
{ name: "categories", fields: ["name"], many: true }]
})
results.tasks[0].type.id;
/* (property) tasks: {
id: any;
description: any;
taskType: {
name: any;
id: any;
};
categories: {
name: any;
}[];
}[] */
}
go()
Full code for interface is below – here is the playground link.
type SortDirection = string
type OrderClause = Array<{
[key: string]: SortDirection
}>
type LegacyOrderClause = {
[key: string]: SortDirection
}
type QueryFilter = Record<string, any> | QueryFilter[]
type QueryField = string | QueryFieldObject
type QueryFieldObject = {
name: string
many?: boolean
fields?: QueryField[]
alias?: string
filter?: QueryFilter
}
interface Query {
readonly table: string
readonly alias?: string
readonly fields: QueryField[]
readonly limit?: number
readonly offset?: number
readonly filter?: QueryFilter
readonly order?: OrderClause | LegacyOrderClause
}
export type ExtractTable<Q extends Query> = Q["alias"] extends string ? Q["alias"]: Q["table"]
type QueryResult<Q extends Query> = {
[K in ExtractTable<Q>]: FieldToData<Q["fields"][number]>[]
}
type OrArray<T, B> =
B extends true ? T[] : T
type FieldToData<F extends QueryField> = { [T in F as (
T extends string ? T :
T extends QueryFieldObject ? (T["alias"] extends string ? T["alias"] : T["name"]) :
never
)]:
T extends string ? any :
T extends QueryFieldObject ? OrArray<
FieldToData<NonNullable<T["fields"]>[number]>, T["many"]
> :
never
} & {}
const getTableRowsFromDb = async (query: Query) => {
console.log("runs query and gets rows", query)
return [] as any[]
}
class Orm {
async query<const Q extends Query>(query: Q): Promise<QueryResult<Q>> {
return {
[query.table]: await getTableRowsFromDb(query)
} as any as QueryResult<Q>
}
}
async function go() {
const orm = new Orm()
const results = await orm.query({
table: "tasks",
limit: 23,
fields: [
"id",
"description",
{ name: "taskType", alias: "type", fields: ["id", "name"] },
{ name: "categories", fields: ["name"], many: true }]
})
results.tasks[0].type.id;
/* (property) tasks: {
id: any;
description: any;
type: {
name: any;
id: any;
};
categories: {
name: any;
}[];
}[] */
}
go()
2