#Why value is unknown?

45 messages ยท Page 1 of 1 (latest)

red sail
#

...

radiant templeBOT
#
OnkelTem#4669

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
...```

red sail
#

I don't get why my attempt of adding conditional didn't work

heavy basin
#

it's because of the | string

radiant templeBOT
#
That_Guy977#5882

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> = {
...```

red sail
#

yep, but how to do it then? Columns can have extra keys

heavy basin
#

not sure you can

#

due to contravarience

red sail
#

It is confusing. I really don't see any reason why it doesn't work

heavy basin
#

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

red sail
#

OK, but why it doesn't separate in the render line?

#

There I say: if K extends keyof T...

heavy basin
#

K is already a string. string doesn't extend keyof { id: number; name: string; }

red sail
#

meh

#

This doesn't work as well ๐Ÿ˜ฆ

heavy basin
#

unions wouldn't do what you want

#

intersections would be closer, however due to:

#

!:index%

radiant templeBOT
#
Gerrit0#7591
`!gerrit0:index-signatures`:

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

heavy basin
#

!:varience

red sail
#

I tried intersection already... it didn't work yea

heavy basin
#

!:variance

radiant templeBOT
#
T6#2591
`!t6:variance`:

Here's the example with Dog and Animal, explaining co/contra/in variance:

  • Covariance: () => Dog is assignable to () => Animal, because Dog is assignable to Animal; it "preserves the direction of the assignability"
  • Contravariance: (Animal) => void is assignable to (Dog) => void, because something that expects an Animal can also take a Dog; it "reverses the direction of the assignability"
  • Invariance: (Animal) => Animal is not assignable to (Dog) => Dog, because not all returned Animals are Dogs, and (Dog) => Dog is not assignable to (Animal) => Animal, because something expecting a Dog cannot take any other kind of Animal
heavy basin
#

due to these two, intersection doesn't work

red sail
#

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()

heavy basin
#

due to contravariance

red sail
#

yep

#

why this problem is not being addressed?

#

I mean, there should be a way because I as a human see it's possible ๐Ÿ™‚

heavy basin
#

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

red sail
#

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 ๐Ÿ™‚

radiant templeBOT
#
OnkelTem#4669

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
...```

red sail
#

Something like this. How does it look?

#

However this would require to make the E type...

#

Even better:

radiant templeBOT
#
OnkelTem#4669

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
...```