Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在typescript中反射并映射类型化参数形状? 上下文_Typescript_Codegen - Fatal编程技术网

在typescript中反射并映射类型化参数形状? 上下文

在typescript中反射并映射类型化参数形状? 上下文,typescript,codegen,Typescript,Codegen,我正在尝试构建一个codegen工具。我喜欢使用GraphQL,但是,当我拥有完整的堆栈时,前端使用严格定义的gql查询调用后端似乎有点愚蠢。GQL是强类型的,因此我应该能够提供强类型的查询和响应 问题 我不知道如何构建一个接口,这样我就可以递归地将一个参数从输入类型映射到目标类型。具体来说,我想将我的查询请求类型映射到gql查询响应类型 const query: QueryRequest<Food.IFood> = { name: true // true ==> imp

我正在尝试构建一个codegen工具。我喜欢使用GraphQL,但是,当我拥有完整的堆栈时,前端使用严格定义的gql查询调用后端似乎有点愚蠢。GQL是强类型的,因此我应该能够提供强类型的查询和响应

问题 我不知道如何构建一个接口,这样我就可以递归地将一个参数从输入类型映射到目标类型。具体来说,我想将我的查询请求类型映射到gql查询响应类型

const query: QueryRequest<Food.IFood> = {
  name: true // true ==> implies inclusion in response
}
const res = await client.food(query)
console.log(res.name) // PASS - should compile
console.log(res.nodeId) // FAIL - should not compile. `nodeId` was not present in query

// Food.IFood is a TS interface, representative of my GQL schema.  GQL => TS interfaces is a solved codegen problem already
// ref: https://github.com/cdaringe/gql-ts-client-codegen/blob/master/src/__tests__/fixture/namespace.ts
const查询:QueryRequest={
name:true//true==>表示包含在响应中
}
const res=等待客户端食物(查询)
console.log(res.name)//PASS-应该编译
console.log(res.nodeId)//失败-不应编译`查询中不存在nodeId`
//IFood是一个TS接口,代表我的GQL模式。GQL=>TS接口已经是一个已解决的codegen问题
//参考:https://github.com/cdaringe/gql-ts-client-codegen/blob/master/src/__tests__/fixture/namespace.ts
  • QueryRequest
    将my
    Food.IFood
    接口(不完全)映射到一个新类型,其中键映射到bools,表示包含GQL字段
  • 但是,每个客户机方法都需要嗅探传递的
    QueryRequest
    以获得显式形状,并以某种方式将该显式形状映射到
    Partial
    • Cleary我不想要一个
      部分
      ——一个
      部分
      对于存在哪些字段是不明确的。我希望客户机的响应具有明确的字段成员身份,作为输入的函数
我知道上面对我的GQL客户机的描述在很大程度上过于简化,并且省去了与所有GQL特性兼容所需的其他复杂性。那很好。我在这篇文章中的主要目的是严格地看看是否有一种方法可以实现这种反射类型映射

我已经开始勾勒出一个硬编码的目标
client.ts
文件,我希望它的潜在输出如下所示:


任何意见都将不胜感激!谢谢。

不幸的是,您需要的基本是约束变量的类型,同时让编译器推断该变量的类型。不幸的是,这不可能直接实现

实现所需行为的唯一方法是使用函数。函数可以具有对其放置约束的泛型类型参数,但最终类型参数将从传入的实际对象文字推断:

type QueryRequest<T, K extends keyof T> = {
    keys: Record<K, boolean>
} 

function buildQueryRequest<T>() {
    return function <P extends keyof T> (o:Partial<Record<P, boolean>>) : QueryRequest<T, P>{
        return null!;
    }
}


interface IFood {
    name: string;
    nodeId: number;
}


type QueryResult<T, K extends keyof T> = Pick<T, K>
declare class Client {
    food<K extends keyof IFood>(q: QueryRequest<IFood, K>) : Promise<QueryResult<IFood, K>>
}

(async function (client: Client) {
    const query = buildQueryRequest<IFood>()({
        name: true // true ==> implies inclusion in response
    })
    const res = await client.food(query)
    console.log(res.name) // PASS - should compile
    console.log(res.nodeId) // error
})
类型QueryRequest={
关键字:记录
} 
函数buildQueryRequest(){
返回函数(o:Partial):QueryRequest{
返回null!;
}
}
界面友好{
名称:字符串;
nodeId:数字;
}
类型QueryResult=Pick
声明类客户端{
食物(q:QueryRequest):承诺
}
(异步函数(客户端:客户端){
const query=buildQueryRequest()({
name:true//true==>表示包含在响应中
})
const res=等待客户端食物(查询)
console.log(res.name)//PASS-应该编译
console.log(res.nodeId)//错误
})

buildQueryRequest
是一个函数,它返回一个函数(即一个curried函数),以便指定第一个参数并推断第二个参数。

hey@titian,感谢您的反馈。受你帖子的启发,我做了一个更紧凑的尝试。我很接近,但是,在我的impl中,
QueryResult
仍然不是完全有界的——它仍然遭受失败,认为来自Food.IQuery的所有键都可以在结果中使用。我有一个压缩到约40 LOC的示例。介意看一眼吗@我现在正在旅行,这个评论很可能会丢失。。。在gitter上给我写信,我明天会看一看。gitter上也有相同的用户名:-)@cdaringe我认为您需要使用
函数exec

(query:P)