V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
azh7138m
V2EX  ›  问与答

typescript 类型问题

  •  2
     
  •   azh7138m · 2019-01-25 14:46:19 +08:00 · 3449 次点击
    这是一个创建于 2136 天前的主题,其中的信息可能已经有所发展或是发生改变。

    泛型的参数是个泛型的话,要怎么写呢?

    class Foo<T> {
      echo(bar: T) {
        return bar
      }
    }
    
    function box(klass) {
      return klass
    }
    
    
    const wraped = box(Foo)
    

    想让 wraped 类型是

    class <T> {
      echo(bar: T): void
    }
    

    Playground

    相关 issue

    Allow classes to be parametric in other parametric classes

    第 1 条附言  ·  2019-01-25 16:52:00 +08:00
    第 2 条附言  ·  2019-01-25 18:02:28 +08:00

    是 react 下的一个场景,我希望 injectSheet 之后的类型是一个泛型,主要是这种需求,比如这种场景

    antd Table 在 TypeScript 中使用

    我现在要写的是一个Table组件的类型,希望 columns 与 dataSource 之间的类型是经过校验的,也就是希望导出的类仍然是一个泛型。

    11楼 最接近我想要的东西,附 链接

    第 3 条附言  ·  2019-01-26 14:44:53 +08:00

    我想要的东西大概是

    class Table<T> {
      data: T[]
      echo: (record: T) => void
    }
    
    function inject<P extends new (...args: any[]) => any>(Component: P) {
      return class Test<T> extends Component<T> {
    
      }
    }
    
    const WrapedTable = inject(Table)
    

    问题在P必须是一个确定的类型,ts也会报错 No base constructor has the specified number of type arguments.

    @chengluyu @momocraft @wly19960911

    第 4 条附言  ·  2019-01-26 18:51:24 +08:00

    按照我的理解,是做不到的了,只能自己胡乱 as 一下凑合着用

    you can only extend object types, in other words something that of a known structure

    参见以下讨论

    issue

    pull

    22 条回复    2019-01-25 17:44:23 +08:00
    momocraft
        1
    momocraft  
       2019-01-25 15:11:17 +08:00
    hkt..? TS 不直接支持,有一些民间的尝试,如 https://medium.com/@gcanti/higher-kinded-types-in-typescript-static-and-fantasy-land-d41c361d0dbe (fp-ts io-ts 等的作者)
    binux
        2
    binux  
       2019-01-25 15:12:40 +08:00
    function box(klass) {
    return new klass()
    }
    wly19960911
        3
    wly19960911  
       2019-01-25 15:23:46 +08:00
    强制类型转换
    azh7138m
        4
    azh7138m  
    OP
       2019-01-25 15:26:34 +08:00 via Android
    @wly19960911 要保留一个泛型参数,不要特化


    @momocraft fp-ts 我知道,那这个 hkt 我要怎么构造? *->*->* 里面的第二个星应该是一个参数,不是一个特化后的类型


    @binux 可我是要返回一个新的 class (
    wly19960911
        5
    wly19960911  
       2019-01-25 15:28:40 +08:00
    @azh7138m #4 是继承吗? 非声明的情况怎么保留一个泛型啊。。。
    azh7138m
        8
    azh7138m  
    OP
       2019-01-25 15:33:31 +08:00 via Android
    @wly19960911 是,所以我贴了一个 issue (
    ts 源自 js 的语法,所以可以动态创建 class,但是这里类型我不会写了
    对应实际问题 https://github.com/cssinjs/jss/issues/972
    chengluyu
        9
    chengluyu  
       2019-01-25 15:37:19 +08:00
    原生 TypeScript 你构造不出来的,用 Haskell 写的话是

    forall a. a -> (forall b. b -> a)

    这才是你想要的东西。
    chengluyu
        10
    chengluyu  
       2019-01-25 15:39:57 +08:00
    @momocraft 这样写的坏处就是你丧失了 TypeScript 编译器提供的类型推断……
    chengluyu
        12
    chengluyu  
       2019-01-25 15:46:47 +08:00
    @azh7138m 可以是可以,毕竟 JavaScript 是动态类型语言,什么都能做。但是 TypeScript 的 type reducer 只能推断 rank 1 type,为了这个需求需要重写一个 rank-N type reducer,我觉得 TypeScript 官方不会给这个任务高优先级的……
    wly19960911
        13
    wly19960911  
       2019-01-25 15:53:53 +08:00
    看来这个东西是我理解错误了。

    这个东西是函数式编程的? 这个意思看起来是 mixins 的味道,更像多继承的功能,实际上 js 原生就能实现的一个东西,但是我没有注意到 ts 能不能实现,丢人了。
    wly19960911
        14
    wly19960911  
       2019-01-25 15:54:44 +08:00
    @wly19960911 #13 并不是说不能实现,而是要充分利用 ts 能给的特性下去实现并且进行类型判断
    chengluyu
        15
    chengluyu  
       2019-01-25 15:55:48 +08:00
    @momocraft 我试了一下,其实是可以推断的,但是 TypeScript 的推断比较取巧。

    见图: https://imgur.com/a/51faYNU
    chengluyu
        16
    chengluyu  
       2019-01-25 15:58:50 +08:00   ❤️ 1
    @wly19960911 其实就是在不 instantiate 一个 generic type 的情况下把这个 generic type 的名字用在 generic parameter 里。

    我刚刚试了一下其实 TypeScript 可以推断,只要把 box 这个函数的类型标注出来就好了。
    momocraft
        17
    momocraft  
       2019-01-25 16:00:15 +08:00
    @chengluyu
    把 klass 原样返回是这样的,如果新的 class (我也不知道 box 本来打算做什么)不天然和 klass 同类型,至少我们还可以 as 过去 lol
    chengluyu
        18
    chengluyu  
       2019-01-25 16:06:06 +08:00
    @momocraft
    只能问楼主想用 box 做什么了。
    其实我觉得结合 TS 的 conditional type 和 infer 关键字应该能写出大部分类型来。
    mooncakejs
        19
    mooncakejs  
       2019-01-25 16:11:47 +08:00
    有点没理解,是要:
    class Foo<T> {
    echo(bar: T) {
    return bar
    }
    }
    type Construct<T> = { new(...args: any[]): T }

    function box<T>(klass: { new(): T }): T {
    return new klass()
    }
    const wraped = box(Foo) as Foo<number> // 这一步只能 as

    wraped.echo(1)
    momocraft
        20
    momocraft  
       2019-01-25 16:17:30 +08:00
    @chengluyu 嗯,类型计算能做很多.. 我试过用 mapped type 写一个“完全的” Readonly,但有类型递归 (直接或间接递归)时就直接报错了。目前的版本是 https://gist.github.com/jokester/e6a4c11f4d2bb22fbbc48b547f49f980
    wly19960911
        21
    wly19960911  
       2019-01-25 16:18:24 +08:00
    @chengluyu #18 我试了下的确不错,但是问题就在于这个 泛型了,你的例子很适合基础类型的扩展,但是基础类型没意义啊。

    但是如果我进行一次继承操作 lz 所说的灵活性就行了,主要现在 echo 方法难道这么广泛的需要 mixin 进去吗。

    否则 echo 里面需要执行什么操作呢,我也在好奇。我是不是说如果这么广泛的时候我直接写个静态方法提取出来操作就可以了?初学只是讨论下。

    https://www.typescriptlang.org/play/index.html#src=class%20Foo%3CT%20extends%20Human%3E%20%7B%0D%0A%20%20%20%20constructor(readonly%20data%3A%20T)%20%7B%7D%3B%0D%0A%20%20%20%20echo()%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20this.data.name%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20Human%20%7B%0D%0A%20%20%20%20name%20%3D%20'213'%3B%0D%0A%7D%0D%0A%0D%0Afunction%20box%3CK%3E(f%3A%20K)%3A%20K%20%7B%0D%0A%20%20%20%20return%20f%3B%0D%0A%7D%0D%0A%0D%0Aconst%20WrappedBar%20%3D%20box(Foo)%3B%0D%0A%0D%0Aconst%20a%20%3D%20%20new%20WrappedBar(new%20Human())%3B%0D%0A%0D%0Aa.echo()%3B%0D%0A
    azh7138m
        22
    azh7138m  
    OP
       2019-01-25 17:44:23 +08:00
    @chengluyu
    @momocraft
    是需要一个泛型,不要一个实例化后的类型,对应实际问题在附言中。

    是 react 下的一个场景,我希望 injectSheet 之后的类型是一个泛型,主要是这种需求,比如这种场景
    https://ant.design/components/table-cn/#%E5%9C%A8-TypeScript-%E4%B8%AD%E4%BD%BF%E7%94%A8
    我希望 columns 与 dataSource 之间的类型是经过校验的,也就是希望导出的类仍然是一个泛型
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2642 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 11:05 · PVG 19:05 · LAX 03:05 · JFK 06:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.