Custom utility types (generic types) for classes `IsClass` of TypeScript
I am trying to create a generic type
to make sure the first parameter to be a class. However, the factory function parameter cannot be replaced by a generic type
.
The following upper parts were my attempts. The last part were a working example that directly write the extends ...
which worked.
Why does it works inside a function, but not works as a generic type
IsClass
?
class A {
constructor() {
}
}
class B {}
class C extends B {}
// ERRORS:
type IsClass<T extends new (...args: any) => InstanceType<T>> = T
type IsClass2<T> = T extends new (...args: any) => InstanceType<T>? T: never
type X = IsClass<A>
type Y = IsClass2<A>
function someFactoryError<T>(clx: IsClass<T>) {
return new clx()
}
someFactoryError(A)
function someFactoryError2<T>(clx: IsClass2<T>) {
return new clx()
}
someFactoryError2(A)
// WORKS:
function someFactoryWorks<T extends new (...args: any) => InstanceType<T>>(clx: T) {
return new clx()
}
const a0 = someFactoryWorks(A)
const b0 = someFactoryWorks(B)
Related:
do you know?
how many words do you know
See also questions close to this topic
-
How can I get toast-ui editor content?
I am a student studying. I think I'm doing it conceptually wrong.
I'm trying to use vue3 and type script And I'm going to use toast-ui editor.
I get some errors.
- refEditor.value.invoke is not a function
How can I get toast-ui editor content?
this is my code
<template> <div class="markup-tables flex"> <va-card :title="$t('tables.stripedHoverable')"> <va-card-content> <div id="refEditor" ref="refEditor"></div> <br /> <div class="row justify--end paginationButtons-left"> <va-button class="mr-2 mb-2">List</va-button> </div> <div class="row justify--end paginationButtons-right"> <va-button class="mr-2 mb-2" @click="getHTML">Save</va-button> </div> </va-card-content> </va-card> </div> </template> <script lang="ts"> import '@toast-ui/editor/dist/toastui-editor.css' import Editor from '@toast-ui/editor' import { defineComponent, onMounted, ref } from 'vue' import data from '@/data/tables/markup-table/data.json' export default defineComponent({ name: 'BoardWrite', setup() { const refEditor = ref(null) const getHTML = () => { console.log('getHTML test') let html = refEditor.value.invoke('getHtml') console.log(html) // ERROR } onMounted(() => { const editor = new Editor({ el: refEditor.value, height: '700px', initialEditType: 'markdown', previewStyle: 'vertical', }) editor.getMarkdown() }) return { getHTML, refEditor, } }, }) </script>
-
Async function passed as prop into React component causing @typescript-eslint/no-misused-promises error
I have the following asynchronous submitNewPatient function which is throwing @typescript-eslint/no-misused-promises error message from elint. Is it possible to adjust the function such that it removes this error?
const submitNewPatient = async (values: PatientFormValues) => { try { const { data: newPatient } = await axios.post<Patient>( `${apiBaseUrl}/patients`, values ); dispatch({ type: "ADD_PATIENT", payload: newPatient }); closeModal(); } catch (e: unknown) { if (axios.isAxiosError(e)) { console.error(e?.response?.data || "Unrecognized axios error"); setError( String(e?.response?.data?.error) || "Unrecognized axios error" ); } else { console.error("Unknown error", e); setError("Unknown error"); } } };
Component used to pass function as a prop:
<AddPatientModal modalOpen={modalOpen} onSubmit={submitNewPatient} error={error} onClose={closeModal} />
I have also tried the following which removes the eslint error message based. However, seems like I am not entering the async code block (perhaps not triggering the async() function):
const submitNewPatient = (values: PatientFormValues) => { async () => { try { const { data: newPatient } = await axios.post<Patient>( `${apiBaseUrl}/patients`, values ); dispatch({ type: "ADD_PATIENT", payload: newPatient }); closeModal(); } catch (e: unknown) { if (axios.isAxiosError(e)) { console.error(e?.response?.data || "Unrecognized axios error"); setError( String(e?.response?.data?.error) || "Unrecognized axios error" ); } else { console.error("Unknown error", e); setError("Unknown error"); } } }; };
-
Read each name in Array list to create seperate object for
I have a file that has student names, age, and an id number. I have a student class that holds the everything above for each student object. I stored all the names, id numbers. and age separately in an array list. Now im trying to assign the info to create a student object.
public class Student { private String lName; private int idNumber; private int age; public Student() { lName = ""; idNumber = 0; age = 0; } public Student(String l, int i, int a) { lName = l; idNumber = i; age = a; } public void setName(String last) { lName = last; } public String getName() { return lName; } public void setIdNum(int num) { idNumber = num; } public int getIdNum() { return idNumber; } public void setAge(int a) { age = a; } public int getAge() { return age; } }
My Text File looks something like this: This info is stored in parallel array lists. I don't quite get how to implement this into an object to pass it into my second contractor method.
Josh 2134 19 Smith 5256 21 Rogers 9248 19 Andrew 7742 20
Here's what I've tried;
public static void main(String[] args) { String file = "studentData.txt"; Scanner reader = new Scanner(file); ArrayList<String> lastNames = lNames(file); ArrayList<Integer> idNumbers = idNum(file); ArrayList<Integer> ageList = ages(file); Scanner input = new Scanner(System.in); Student s1 = new Student(); // confused about how to implement this constructor with the textile info for (int i = 0; i<idNumbers.size(); i++) { Student user = new Student(lastNames.get(i), idNumbers.get(i), ageList.get(i)); } //user enters idNumber to display age System.out.println("Enter ID Number"); //exception handling to be added int idNum = input.nextInt(); for (int i = 0; i<idNumbers.size(); i++) { if (idNum == idNumbers.get(i)) { s1.setAge(ageList.get(i)); System.out.println(s1.getAge()); } } }
-
Nested list in C# with layers
I am not an expert coder and I have just started learning about Generic data types. What I am trying to code is a List inside of a list inside of a list .
For example- at the first level - I want numbers each inside of a list
Layer 1 list1=[1,2,3,4,5,6,7,8,9,10......1000] ,
At the 2nd layer I'd like list from 1st layer added as an element to a parent list 2 when layer 1 meets certain condition- ex layer 1 reaches max=10
List2=[List1[0:10],List1[10:20],List1[20:30], .....] ,
At layer 3, i'd like to repeat the process, all elements of layer 2 get added as an element to a new parent list 3 when layer 2 meets a max condition. list3[0]=[list2[0:10],list2[10:20],list2[20:30]..... and so on.
Only the first layer would have integer values, the successive layer would be a wrapping of it's the previous layer. How can I code this in C#?
Thanks!
-
How to get generic types of subclass in Python
I have a generic parent class and a child class that implements the parent with a specific type:
T = TypeVar("T") class Parent(ABC, Generic[T]): def get_impl_t(self): pass class Child(Parent[int]): pass
I'd like to get the type of the child class from the parent (see
get_impl_t()
).I'm pretty sure this isn't possible without some hackery (
inspect.getsource()
?) because of type erasure. It's wouldn't work if this didn't have a class hierarchy.The obvious workaround is add an abstract classmethod that gets the type or add a parameter to the parent class's constructor:
class Parent(ABC, Generic[T]): def__init__(self, param_cls: Type[T]) -> None: self.param_cls = param_cls # or @classmethod @abstractmethod def get_param_cls() -> Type[T]: pass
This would add some maintenance overhead, so I want to make sure I'm not missing anything.
-
Typescript factory of generic interface in
I'm creating a factory like this:
interface IOperator<T> { parse(arg: string): T; doSomething(value: T): void; }
2 operators:
class StringOperator implements IOperator<string> { parse(arg: string) { return arg; } doSomething(value: string) { /* some logic */} } class NumberOperator implements IOperator<number> { parse(arg: string) { return parseInt(arg, 10); } doSomething(value: number) { /* some logic */} }
the factory:
const operatorMap = { STRING: StringOperator, NUMBER: NumberOperator, }; export const supportedOperators = Object.keys(operatorMap); type OperatorMap = typeof operatorMap; export type Operators = keyof OperatorMap; type Tuples<T> = T extends Operators ? [T, InstanceType<OperatorMap[T]>] : never; type SingleOperators<K> = [K] extends (K extends Operators ? [K] : never) ? K : never; type ClassType<A extends Operators> = Extract<Tuples<Operators>, [A, any]>[1]; export class OperatorFactory { static create<K extends Operators>(k: SingleOperators<K>): ClassType<K> { return new operatorMap[k](); } }
and use them like this:
const operator = OperatorFactory.create(operatorName); const theValue = operator.parse(theArgument); return operator.doSomething(theValue);
I get the message:
const theValue: string | number Argument of type 'string | number' is not assignable to parameter of type 'never'. Type 'string' is not assignable to type 'never'.ts(2345)
Please check Playground Link for details.
I assume the issue is
theValue
can bestring | number
but.doSomething()
only accept one value type.If I let
.doSomething(theValue: unknown)
then do the conversion insidedoSomething
it will work, but it's not what I expected.What should I do to make this pattern work in good practice pattern?
Thanks,
-
How do i provide property missing?
I try to create a factory function for graphql resolver but i get error for the function return.
I don't want turn false tsconfig "declaration". Please existing way to resolve this ?
-
Factory function for mongoose transaction session on Typescript
I have a lot of function like these
currency.service.ts async createCurrencyOnSession(createCurrencyDto: CreateCurrencyDto): Promise<ResponseCurrencyDto> { const session = await this.currencyModel.startSession(); session.startTransaction(); try { const currency = await this.createCurrency(createCurrencyDto, {session}); await session.commitTransaction(); return currency; } finally { await session.endSession(); } }
user.service.ts async createUserOnSession(createUserDto: CreateUserDto): Promise<ResponseUserDto> { const session = await this.userModel.startSession(); session.startTransaction(); try { const user = await this.createUser(createUserDto, {session}); await session.commitTransaction(); return user; } finally { await session.endSession(); } }
I don't like many try catch on code so I try to edit
currency.service.ts async createCurrencyOnSession( createCurrencyDto: CreateCurrencyDto, ): Promise<CurrencyResponseDto> { const session = await this.currencyModel.startSession(); session.startTransaction(); return handleSession(this.createCurrency(createCurrencyDto, { session })); }
export const handleSession = async (handler) => async (dto, options: ISessionOptions) => { try { return await handler(dto, options); } finally { await options.session.endSession(); } };
I can see error on Typescript because the main function return a specific interface:
CurrencyResponseDto
,UserResponseDto
. How can I add dynamic interface to returnCurrencyResponseDto
,UserResponseDto
, ... on factory function. Could you help me to make it clean or suggest a better version on problem. Thanks -
function declaration for a generic function return wrapper
How to declare the function
wraps
that takes any function and returns a version of it that differs only in returning an object that wraps the original return type in its propvalue
... and support generics
try it heretype Fn = (...args: any) => any declare function wraps<F extends Fn>( f: F ): (...args: Parameters<F>) => { value: ReturnType<F> } declare function aFunction<T>(t: T): { a: T } const x = aFunction(100) // const x: { a: number } const wf = wraps(aFunction) // const wf: (t: unknown) => { value: { a: unknown } } const y = wf(100) // const y: { value: { a: unknown } } // expected: const y: { value: { a: number } } y.value.a.toExponential() // Property 'toExponential' does not exist on type 'unknown'. ts(2339)
-
Return subset of union depending on class in generic function
This is very much like my other question, but this time using classes instead of plain objects.
class Error1 extends Error { constructor(message: string, public arg1: string) { super(message); } } class Error2 extends Error { constructor(message: string, public arg2: string) { super(message); } } type MyError = Error1 | Error2; type Constructor<T> = new (...args: any) => T; function filterErrors<E extends MyError>(errors: MyError[], classes?: Constructor<E>[]): E[] { if (!classes) return errors as E[]; return errors.filter((error) => classes.some((klass) => error instanceof klass)) as E[]; } const e1 = new Error1("e1", "whatever"); const e2 = new Error2("e2", "whatever"); const errors = [e1, e2] const f1 = filterErrors(errors); // OK const f2 = filterErrors(errors, [Error1]); // OK const f3 = filterErrors(errors, [Error1, Error2]) // Error
Also available in Typescript playground.
The error is:
Types of construct signatures are incompatible. Type 'new (message: string, arg2: string) => Error2' is not assignable to type 'new (...args: any) => Error1'. Property 'arg1' is missing in type 'Error2' but required in type 'Error1'.(2419)
I can work around it by specifying the generic parameter in the call site:
const f3 = filterErrors<Error1 | Error2>(errors, [Error1, Error2])
But that's obviously not ideal.
PS. If I remove the extra constructor arguments in
Error1
andError2
(which I'm not willing to do in practice), then the error goes away, butf3
is typed asError1[]
-- I'd expect(Error1 | Error2)[]