DEV Community

Discussion on: My confusions about TypeScript

Collapse
 
nickytonline profile image
Nick Taylor

For the first one

function handleRelations(modelClass: extends Model) ...

here is a very simple TypeScript Playground example example.

TLDR;

class Model {
    // Some awesome code
}

function handleRelations(modelClass: Model) {
   // do something with modelClass
}

In terms of readability for

function converter(input: Map<{ [key: string] : any }, { [key: string] : any }>): Map<{ [key: string] : any }, { [key: string] : any }>

see this TypeScript Playground example

TLDR;

function converter(input: Map<{ [key: string]: any }, { [key: string]: any }>): Map<{ [key: string]: any }, { [key: string]: any }> {
    // awesome code
    return input;
}

// can become

function converterWithBetterTypes(input: Map<Record<string, any>, Record<string, any>>): Map<Record<string, any>, Record<string, any>> {
    // Note: Record<T> is a built-in TypeScript type
    // awesome code
    return input;
}

// can become
// Probably best not to use any
type ConverterShape<T extends any = any> = Map<Record<string, T>, Record<string, T>>

function converterWithReadableTypes(input: ConverterShape): ConverterShape {
    // awesome code
    return input;
}

When I have a chance, I'll check out the other issues you're having.

Collapse
 
kenbellows profile image
Ken Bellows • Edited

Huh, Record<T> is a pretty handy trick. Definitely nicer than the bare syntax. And yeah, in cases where it gets too complicated I definitely do declare little types, but it seems like a lot of overhead to have to declare a local type for every function that uses Maps or Sets of objects like that... I'll have to think about that one.

Regarding passing around classes and subclasses, in your example, modelClass: Model is still and instance of some class extending Model, rather than a class itself. I need to reference the classes themselves to get at static methods and properties. Here's a playground example (in a broken state) showing what I mean.

Thanks for the responses!

Collapse
 
nickytonline profile image
Nick Taylor

Ahh, I see what you mean. My bad. You can do this

TLDR;

class Model {
    // Some awesome code
}

function handleRelations(modelClass: typeof Model) {
    return modelClass;
}

Does that handle your use case?

Thread Thread
 
kenbellows profile image
Ken Bellows

Oh man yes it does, that's exactly what I was looking for! I didn't realize that was a thing! Thanks!

Thread Thread
 
coly010 profile image
Colum Ferry

Or even better using generics:

function handleRelations<T extends Model>(modelClass: T) {
    return modelClass;
}
Thread Thread
 
nickytonline profile image
Nick Taylor

Generics for sure, but it still needs to be typeof Model as he doesn’t want an instance of the class.

Thread Thread
 
coly010 profile image
Colum Ferry

I missed that. In that case, he shouldn't use a class here, rather:

export type Model = {...}

// Or

export interface Model {...}
Thread Thread
 
nickytonline profile image
Nick Taylor • Edited

I rarely use classes aside from React components (pre-hooks) as I prefer functions even though I'm not a full FP kind of person, but they are still used by many. 😉

For sure, a type is an option. It just depends on what he wants to do in that function. If an interface or type is used and he wanted to create an instance of the Model class, using an interface or type would not work. If he wanted to use it for duck typing in his function, then an interface or type would suffice.

interface SomeModelInterface {
    someMethod: () => boolean;
}

class Model implements SomeModelInterface {
    someMethod() {
        return true;
    }
}

function handleRelations(modelClass: typeof Model) {
    const instance = new modelClass();
    const value = instance.someMethod(); // true;
}

function handleRelations2(modelClass: SomeModelInterface) {
    const instance = new modelClass(); // errors
    const value = modelClass.someMethod(); // All good
}

TypeScript playground snapshot

Here's a sample TypeScript Playground for those interested.

Thread Thread
 
coly010 profile image
Colum Ferry

Very interesting. I didn't realise you could combine new with typeof T params.

Thread Thread
 
kenbellows profile image
Ken Bellows

Yeah Model isn't my class, it's provided by Objection.js, an ORM library I'm using. As mentioned in the post, I need to access static properties of various subclasses of Model, so I need to pass around the classes themselves.