#Why value is unknown?
45 messages ยท Page 1 of 1 (latest)
Preview:```ts
type Obj = Record<string, unknown>
type Columns<T extends Obj> = {
[K in keyof T | string]?: {
render?: (
value: K extends keyof T ? T[K] : unknown
) => string
}
}
type Foo = {
id: number
name: string
}
const fooColumns: Columns<Fo
...```
I don't get why my attempt of adding conditional didn't work
it's because of the | string
Preview:```ts
type Obj = Record<string, unknown>
type Columns<T extends Obj> = {
[K in keyof T]?: {
render?: (
value: K extends keyof T ? T[K] : unknown
) => string
}
}
type Foo = {
id: number
name: string
}
const fooColumns: Columns<Foo> = {
...```
yep, but how to do it then? Columns can have extra keys
keyof T | string is string
K in string acts like K: string
keyof T is a union of strings, so like in your example case, keyof T would be 'id' | 'name', so keyof T | string would be 'id' | 'name' | string, which collapses to just string
OK, but why it doesn't separate in the render line?
There I say: if K extends keyof T...
K is already a string. string doesn't extend keyof { id: number; name: string; }
unions wouldn't do what you want
intersections would be closer, however due to:
!:index%
Index signatures apply to all members of the type that match the signature. Therefore, the following type is invalid, even though TypeScript does not detect it until you actually try to construct a value which conforms to the type.
type Foo = { a: 1 } & { [x: string]: 2 }
TypeScript does not have a way to specify "everything besides defined keys" since it does not have negated types. This pattern cannot be expressed in TypeScript today. A more TS-friendly version of it puts all of the extra properties on a dedicated key:
type Foo = { a: 1; extra: { [x: string]: 2 } }
negated types: https://github.com/microsoft/TypeScript/pull/29317
!:varience
I tried intersection already... it didn't work yea
!:variance
Here's the example with Dog and Animal, explaining co/contra/in variance:
- Covariance:
() => Dogis assignable to() => Animal, becauseDogis assignable toAnimal; it "preserves the direction of the assignability" - Contravariance:
(Animal) => voidis assignable to(Dog) => void, because something that expects anAnimalcan also take aDog; it "reverses the direction of the assignability" - Invariance:
(Animal) => Animalis not assignable to(Dog) => Dog, because not all returnedAnimals areDogs, and(Dog) => Dogis not assignable to(Animal) => Animal, because something expecting aDogcannot take any other kind ofAnimal
due to these two, intersection doesn't work
So basically TS cannot help with any reasonable table definition
maybe that's the reason why nobody created a single table solution with sensible typing
Most of them provide any as value for the render()
yeah i don't think so
due to contravariance
yep
why this problem is not being addressed?
I mean, there should be a way because I as a human see it's possible ๐
it's not a problem
it isn't though; id is a string, string render functions accept unknown, the id render function should accept unknown
Well, there is still a way. Instead of decorating the original type, make a derived type:
type Extended<T, E> = {
original: T
extra: E
}
and type Columns for this Extended. But I think developers would feel itchy with this one ๐
Preview:```ts
type Obj = Record<string, unknown>
type Extended<T, E> = {
fields: T
extra: E
}
type Columns<T extends Extended<any, any>> = {
fields?: {
[K in keyof T["fields"]]?: {
render?: (
value: T["fields"][K],
row: T["fields"]
) => string
...```
Something like this. How does it look?
However this would require to make the E type...
Even better:
Preview:```ts
type Obj = Record<string, unknown>
type Columns<T extends Obj> = {
fields?: {
[K in keyof T]?: {
render?: (value: T[K], row: T) => string
}
}
extra?: {
[K in string]?: {
render?: (row: T) => string
}
}
}
type Foo
...```