#Can you implement generics with upper bound/`satisfies` somehow

1 messages · Page 1 of 1 (latest)

unreal oracle
#

See the sample here:

https://www.typescriptlang.org/play?#code/PTAEBUAsEsGdTqAVgV1gF1AQwHYJ+gKYBOAZlgMaGhqEAmopA9saERtDgOYBQnRZStQCCAIwqgA3tgBcoUUyYAbQrgA08uThQBbUSQ0U5GYpy6gAvjxAQY8dAE8ADtQpMcANxLp4WJUtAnYiYneyZQEPRodz95RRVcWA1odAByeBx3AFpiQgoUYlhoLzZwnSwAa2p0SGpCAA8sHScVUCLmlWIeRxdQYVhwYhRCWAAecAA+UABeKVAAbQBpfFAqhyZSCABdAH45BWVVPCtrMABNJhRQClxQSCYvVlrc7BwGWEJqyCxMAHdqLiETDSLB7OKHdTyMEHBI4QzQ+JHSzdZzUcAjdD9QbDeCzLFDEajMQUCY8U62RA9ahOaAUCrwS6YIIhbzQEaMYI6UAAeVESDyf2eX2osCa1OCTgQ9gJKwAYtAlAIUb0AAq0ioAdSF2MIo15-Io6A08sVJFADSIb3g+Jxer5AomU1mkh4oAWy04q0I602+oF2HgJoESy25vqlro0uGoB2oGWWkIjy2cj9hpDPBONgAIoQdO4TD9ongNqA1XStSRCDrlWiMWXNUKZqX1RXcjqieINCC5OgZRZSeSoIgsE5mfVoOV2NhrkosLB4L8YBRIPgMLgqPBviUatQfr3oKIUFOSwBRGugAASc4AwvneyhDSxRienXMcIRfgAKACUchPyPJABJHAUmgWImHtQ1QEXWkV0QD5MBQSVfhSFcsEvG87yGR9iGfUkKFnedQA1VDU3QZ9jQVAQwwja0BgJMYXymF03TcHATAfdAWE-IJih+Oo5CvWBb3Y+8cLw785hON0UJqIMSE-UgqJIOR5OISSWLdUBcnQAo8HfX4eUg9ASLk5TiE-Go4AAOkIDQlNNdTXWRTMwEAtgYBwCpQHc35LiUBglGgKpSnkXdRFaLiaA+NomB0IFPPMIKQoAA1FKJYCUkYUtXIgsAYEsUotQgrRyoUZCA6DcEwHc+no20X1C-QPOoJCXFYBQUDeUBP2gTZ3K6ugSAwRQGFqgQdE4ZQmC4BxrhYXJDSUBxvw0XA6HJWgPJ+ANpy4FBoCG+QjzuLBt1qbBDRQWIqQiTY1LClrQEmkDygCKkNFQDBQGSwhyTSwtMrZWAcuYVgVHQYA2IwazyQIud4DI0zIDUijQAe9K4CyuidUYiYNBVCV4GKq1m3LbUCTRtTHSkHh4aIpHUNRk9KMcmiSsjOrcbwgmifZ0n61bKtKZZ9HzJpzTobEriLN4jx+PNQTMNE7CZZ5wJTHlohGHM1TzI0gC3ToJgAGU4oSsweKJuRCZCWANOc1j80OaylBmyy7FsjQrNgayHIEDRmVCb9nKsE56fgdEMGJBAOlzEqfD6cRabdLB9kRXBnNELRdH0LpWOMfduAzMkbFtiLcx7C6nCwYgxWosHoKZ8zTvsVEuYYjsSWgpc4PgEEEQhOEoXToe5AoQfYWRGwh3geLEjFxyQ35zn72oRB30eNgZU9QWKejGDl2eo4FzqbqkKbmpXnNZpHAiYzzxPW+HDIps98rdtiQ0G1CWJR0eAMsRUixlPxR0xOIb81lZIo3Mp+SQadt7DAsJA42Zt4pWW4HA5BoAbC+X8oFYKwoNZ20CLXeuZotzVHbt2cEU8LB3ErEAA

Is this achievable with the latest version of TS?

winged hillBOT
#

@unreal oracle Here's a shortened URL of your playground link! You can remove the full link from your message.

Samu#2603

Preview:```ts
// This is just an interface used for testing
interface Abc { a: boolean, b: number, c: string }
// This type converts all props to optional booleans, it's non-recursive to make the example simpler
type AsTrues<T> = { [K in keyof T]?: boolean }

// You can hover here and see that we get { a?: boolean, b?: boolean, c?: boolean }
...```

elfin magnet
#

satisfies and extends work in the same direction
U extends T, U must be a subtype of T
v satisfies T, v's type must be a subtype of T

#

are you looking for something more like java's super?

#

ts doesn't have that currently

#

extends(java & ts)/satisfies(ts) give upper bounds, super(java) gives a lower bound

#

looks like you want more granular generics here actually

#

moving the Filter generic to the method solves the issue by letting the inferred type be more specific to the call

#

i don't think you need Props entirely, either

winged hillBOT
#
That_Guy977#5882

Preview:```ts
// This is just an interface used for testing
interface Abc { a: boolean, b: number, c: string }
// This type converts all props to optional booleans, it's non-recursive to make the example simpler
type AsTrues<T> = { [K in keyof T]?: boolean }

// You can hover here and see that we get { a?: boolean, b?: boolean, c?: boolean }
...```

elfin magnet
#

@unreal oracle

unreal oracle
#

I wish I could see a diff 🙂

#

hmm, so you basically push the generics and constraints down to the method level for it to work

#

Thanks! I was really hoping it would be possibly somehow. I'll try it out with my larger real case now.

elfin magnet
#

theoretically you could make it yourself, but manual diff here we go

- class WithObject<E, Filter extends AsTrues<E>> {
+ class WithObject<E> {
    constructor(private e: HasConstructor<E>) { }

-   withFilter(filter: Filter) {
+   withFilter<Filter extends AsTrues<E>>(filter: Filter) {
      return new ObjectWithFilter(this.e, filter)
    }
  }

- class ObjectWithFilter<E, Filter extends AsTrues<E>, Props extends PickWhereTrue<E, Filter>> {
+ class ObjectWithFilter<E, Filter extends AsTrues<E>> {
    constructor(private e: HasConstructor<E>, private filter: Filter) { }

-   doSomething(props: PickWhereTrue<E, Filter>) {
+   doSomething(props: Props) {
      console.log(this.e, this.filter, props)
    }
  }
unreal oracle
#

damn, you are like chatGPT 🙂

elfin magnet
elfin magnet
#

or anyone, for that matter

unreal oracle
#

it was supposed to be a compliment 🙂

elfin magnet
#

it really isn't

unreal oracle
#

as in "you have a lot of knowledge and you are very responsive"

elfin magnet
#

chatgpt doesn't have any knowledge

unreal oracle
#

ok, i think we are getting off topic now.

elfin magnet
#

it parrots things it sees without understanding them, humans actually have to understand them

#

so yeah please don't compare anyone to chatgpt, it isn't a compliment

unreal oracle
#

anyway, thanks. I will see if my larger example which this was based on can be fixed by applying this method now.

#

so i guess in general it is better to move the generics and constraints down to the function level if you have a generic class or interface.

elfin magnet
#

not really

#

it isn't an "in general" thing

#

it's just, what is the generic related to?

#

data of the entire object? that goes on the class
a specific operation? that goes on the specific method

#

if something should be specific to an operation, like here, and you put it on the class, that makes the generic apply to all operations of that type, meaning you can't get individually linked operations anymore, they're all of the same type

#

that's a really confusing explanation hold on

winged hillBOT
#
That_Guy977#5882

Preview:```ts
class ExampleA {
identity<T>(v: T): T {
return v;
}
}

class ExampleB<T> {
identity(v: T): T {
return v;
}
}

const a = new ExampleA(); // T doesn't exist yet
const b = new ExampleB(); // T is unknown by default

const resultA = a.identity(0); // correctly infers T
...```

unreal oracle
#

no, I think I already see what you are saying

elfin magnet
unreal oracle
#

Thanks you got me unstuck. Now I think I got to a point where my proof of concept seems to be demonstrated.

#

Do you btw know if there's a way to improve the developer experience for the case where a mapped type maps to {a: number} | ClassWithMembers without that being unioned together into a mess of attributes that the ClassWithMembers supports.

#

I don't want the intellisense to suggest setting up a value that has the props of ClassWithMembers. Instead you should instanstiate the class directly if that's what you wanted to use.

elfin magnet
#

idk about that, sorry

#

ClassWithMembers as a type is really just an interface in the shape of the class

unreal oracle
#

yeah, it would be nice to treat class instances as opaque types that you can't create by setting them up with their individual members for this case though

elfin magnet
#

i think that question would warrant a separate thread

#

i don't know anything about that, sorry

unreal oracle
#

yeah i agree. thanks.

elfin magnet
#

!resolved