泛型的参数是个泛型的话,要怎么写呢?
class Foo<T> {
echo(bar: T) {
return bar
}
}
function box(klass) {
return klass
}
const wraped = box(Foo)
想让 wraped 类型是
class <T> {
echo(bar: T): void
}
相关 issue
是 react 下的一个场景,我希望 injectSheet 之后的类型是一个泛型,主要是这种需求,比如这种场景
我现在要写的是一个Table组件的类型,希望 columns 与 dataSource 之间的类型是经过校验的,也就是希望导出的类仍然是一个泛型。
我想要的东西大概是
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
按照我的理解,是做不到的了,只能自己胡乱 as 一下凑合着用
you can only extend object types, in other words something that of a known structure
参见以下讨论
issue
pull
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 等的作者)
|
2
binux 2019-01-25 15:12:40 +08:00
function box(klass) {
return new klass() } |
3
wly19960911 2019-01-25 15:23:46 +08:00
强制类型转换
|
4
azh7138m OP @wly19960911 要保留一个泛型参数,不要特化
@momocraft fp-ts 我知道,那这个 hkt 我要怎么构造? *->*->* 里面的第二个星应该是一个参数,不是一个特化后的类型 @binux 可我是要返回一个新的 class ( |
5
wly19960911 2019-01-25 15:28:40 +08:00
@azh7138m #4 是继承吗? 非声明的情况怎么保留一个泛型啊。。。
|
6
momocraft 2019-01-25 15:32:06 +08:00
|
7
momocraft 2019-01-25 15:33:01 +08:00
|
8
azh7138m OP @wly19960911 是,所以我贴了一个 issue (
ts 源自 js 的语法,所以可以动态创建 class,但是这里类型我不会写了 对应实际问题 https://github.com/cssinjs/jss/issues/972 |
9
chengluyu 2019-01-25 15:37:19 +08:00
原生 TypeScript 你构造不出来的,用 Haskell 写的话是
forall a. a -> (forall b. b -> a) 这才是你想要的东西。 |
11
momocraft 2019-01-25 15:42:46 +08:00 1
(typeof Foo) 就是 Foo (as a constructor / value) 的类型。如果写可能是
https://www.typescriptlang.org/play/index.html#src=class%20Foo%3CT%3E%20%7B%0D%0A%20%20echo(bar%3A%20T)%20%7B%0D%0A%20%20%20%20return%20bar%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Afunction%20box(klass)%20%7B%0D%0A%20%20return%20klass%20as%20FooConstructor%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20FooConstructor%20%7B%0D%0A%20%20new%3CT%3E()%3A%20Foo%3CT%3E%3B%0D%0A%7D%0D%0A%0D%0Aconst%20wraped%20%3D%20box(Foo)%0D%0A%0D%0Aconst%20w1%20%3D%20new%20wraped%3Cnumber%3E()%3B%0D%0Aw1.echo(1)%3B%0D%0A as 前后仍然都还有类型推断的,只是不连起来 (所以写的人自己负责保证) |
12
chengluyu 2019-01-25 15:46:47 +08:00
@azh7138m 可以是可以,毕竟 JavaScript 是动态类型语言,什么都能做。但是 TypeScript 的 type reducer 只能推断 rank 1 type,为了这个需求需要重写一个 rank-N type reducer,我觉得 TypeScript 官方不会给这个任务高优先级的……
|
13
wly19960911 2019-01-25 15:53:53 +08:00
看来这个东西是我理解错误了。
这个东西是函数式编程的? 这个意思看起来是 mixins 的味道,更像多继承的功能,实际上 js 原生就能实现的一个东西,但是我没有注意到 ts 能不能实现,丢人了。 |
14
wly19960911 2019-01-25 15:54:44 +08:00
@wly19960911 #13 并不是说不能实现,而是要充分利用 ts 能给的特性下去实现并且进行类型判断
|
15
chengluyu 2019-01-25 15:55:48 +08:00
|
16
chengluyu 2019-01-25 15:58:50 +08:00 1
@wly19960911 其实就是在不 instantiate 一个 generic type 的情况下把这个 generic type 的名字用在 generic parameter 里。
我刚刚试了一下其实 TypeScript 可以推断,只要把 box 这个函数的类型标注出来就好了。 |
17
momocraft 2019-01-25 16:00:15 +08:00
@chengluyu
把 klass 原样返回是这样的,如果新的 class (我也不知道 box 本来打算做什么)不天然和 klass 同类型,至少我们还可以 as 过去 lol |
18
chengluyu 2019-01-25 16:06:06 +08:00
|
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) |
20
momocraft 2019-01-25 16:17:30 +08:00
@chengluyu 嗯,类型计算能做很多.. 我试过用 mapped type 写一个“完全的” Readonly,但有类型递归 (直接或间接递归)时就直接报错了。目前的版本是 https://gist.github.com/jokester/e6a4c11f4d2bb22fbbc48b547f49f980
|
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 |