Get the <T> type in Typescript - reactjs

For example in my case I need to reuse the type of a component in React (React.FC) but I want it with optionals props by using Partial<T>.
Is there a way to "get" the Generic <T> from that component type (type TypeTargetComponent = React.FC<T>) ? I would like to do something like : React.FC<Partial<XXXX<typeof TargetComponent>>> where XXXXis the "method" to get what I want.

type ExtractPropsType<T> = T extends React.FC<infer Type> ? Type : never;
This should work if you type typeof TargetComponent

You can use the infer keyword.
Something like this should work:
Updated the answer to include example and fixed the type inferrence issue.
type FC<T> = { data: T }
type InferredValueOf<Comp extends FC<any>> = Comp extends FC<infer T> ? T : never
type Derived<TargetComponent> = TargetComponent extends FC<any> ? FC<Partial<InferredValueOf<TargetComponent>>> : never
type TestType = Derived<FC<{ testValue: "value" }>>
const test: TestType = {
data: {
// testValue is optional now
}
}

Related

Conditional Type Checking based on function parameter

Im writing a custom Hook that can take either one or two strings, or an object with more granular parameters. I wanted to add a conditional type check to check for a type of that param and do some logic based on it. Here are the relevant snippets:
// The hook itself
const [error, loading, data] = useFirestore('posts', 'test'); // in a string version
const [error, loading, data] = useFirestore({...someProps}); // in a object version version
// The types that i defined for them
type queryType<T> = T extends string ? string : documentQueryType;
type docType<T> = T extends string ? string : never;
type documentQueryType = {
collection: string;
query: string[] | string[][];
limit: number;
orderBy: string; // todo limit this to be only special words
order: string; // todo same as above
startAt: number;
endAt: number;
};
// The function that is in the question
export const useFirestore = <T>(query: queryType<T>, doc?: docType<T>) => {...rest of the function
How would I make the last snippet work so when passed an object it sets doc to never, and when passed a string sets the doc to string?
This can be partially achieved with conditional types, but it may not be 100% type-safe. Since doc is optional, it will not be required when the query is a string, and will still allow undefined when query is an object.
However, if these two scenarios are not an issue, this can be achieved with conditional types:
// Simplified type
type DocumentQueryType = {
collection: string;
};
// The two types of queries that are accepted
type QueryTypes = string | DocumentQueryType;
// Given the query type, infer the doc type
type InferDocType<QueryType> = QueryType extends string ? string : never;
const useFirestore = <QueryType extends QueryTypes>(query: QueryType, doc?: InferDocType<QueryType>) => { }
// Valid Examples
useFirestore('posts', 'test');
useFirestore({ collection: "" });
// Valid Examples (may not want these?)
useFirestore('posts');
useFirestore({ collection: "" }, undefined);
// Invalid Examples
useFirestore({ collection: "" }, "test");
// Argument of type '"test"' is not assignable to parameter of type 'undefined'.(2345)
useFirestore('posts', null);
// Argument of type 'null' is not assignable to parameter of type 'string | undefined'.(2345)

how to define custom Map type in typescript?

I'm trying to define a Map type using Typescript generics. what I want is something like this
EntityMap<U, V>, U can be only string or number
this is what I have done so far
export type EntityMapKey = string | number;
export type EntityMap<U, V> = { [K in EntityMapKey]: V};
but when we use it we can put anything as U like below
interface Jobs {
list: EntityMap<Array, JobFile>
}
I want to restrict using any type other than string or number as U, how can we achieve this?
am I missing anything?
U in your EntityMap is not used, the correct implementation should be
export type EntityMapKey = string | number;
export type EntityMap<U extends EntityMapKey, V> = { [K in U]: V};
interface Jobs {
list: EntityMap<string, any>
}

Typescript - return type that is part of whole interface (check if it implements other interface)

I have a generic reducer that's return type is TableState.
const reducerFactory = ..... = (): TableState => ....
TableState:
interface TableState {
filters: Filter;
data: TableData;
isLoading: boolean;
}
Each component's that uses this reducer factory implements TableState.
For example
interface SalesReportState implements TableState {
someCommonField: string;
}
App build fails as the types don't match. I could do someCommonField?: string; but someCommonField should be obligatory.
Is there a Typescript feature that the return type just checks if the table type implements Table State? So the return type would be some type that makes sure it is an instance of TableState, not exactly TableState type.
If you want to know if an object implements TableState, you can use:
instanceof
if (obj instanceof TableState) // returns true if object implements TableState
only works with abstract class
type-guards. Example:
let obj = {}; // an object you want to check
/**
* A discriminator is a property which determines if the object in question is
* a TableState
*/
function isTableState(obj: any): obj is TableState {
return obj &&
obj.filter &&
obj.data &&
obj.isLoading && typeof(obj.isLoading) === 'boolean';
}
// check phase
if (isTableState(obj)) {
// object is automatically casted to TableState
}
PS: If you want to extend an interface with another interface, use extends
EDIT: I don't know the Filter and TableData type, is that an interface or a class? The answer may change again, depending on the type

How to set function's param as a key from interface

I have interface and object which represents this interface:
MyInterface {
variableOne: string;
variableTwo: boolean;
variableThree: boolean;
...
}
Also I have function toggleFunction(x) which gets a key and toggles it in my object.
Which type do I need to set in param x in my toggle function to use it for toggle all boolean key in my object?
For example I need something like: toggleFunction(x: TYPE?)
Use keyof.
function toggleFunction(x: keyof MyInterface): void {
// ...
}
You can use a conditional mapped type that I usually call KeysMatching:
type KeysMatching<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];
And then toggleFunction() can be defined like this:
declare const o: MyInterface; // or wherever it comes from
function toggleFunction(x: KeysMatching<MyInterface, boolean>) {
o[x] = !o[x];
}
toggleFunction("variableTwo"); // okay
toggleFunction("variableThree"); // okay
toggleFunction("variableOne"); // error!
Hope that helps; good luck!
Link to code

TypeScript: Is there any way to have an Array of types using the typeof operator?

Given the following code:
class Type
{
static Property = 10;
}
class Type1 extends Type
{
static Property = 20;
}
class Type2 extends Type
{
static Property = 30;
}
I would like to make a function that can return an array of types that all inherit from the same base, that allows access to the "static side" of the class. For example:
function GetTypes(): typeof Type[]
{
return [Type1, Type2];
}
So now ideally I could go:
GetTypes(0).Property; // Equal to 20
However it doesn't seem like there is syntax for storing multiple typeof types in an array.
Is this correct?
Of course there is. Your code is correct minus the return type of the GetTypes function. (To be clear Steve's answer would solve your issue as well, this is just another approach without making use of interfaces).
Change the return type of the GetTypes function to:
function GetTypes(): Array<typeof Type>
{
return [Type1, Type2];
}
This should to the trick.
The correct way to do this would be to create an interface that describes the properties (or operations) supported by the type (that don't belong to an instance of the type):
interface Test {
x: number;
}
class MyType {
static x = 10;
}
class MyOtherType {
static x = 20;
}
var arr: Test[] = [MyType, MyOtherType];
alert(arr[0].x.toString());
alert(arr[1].x.toString());
No. It is currently only supported for single identifiers. I have made a feature request here: https://typescript.codeplex.com/workitem/1481
Nonetheless you can simply create a dummy interface to capture typeof Type and then use it in an Array i.e:
class Type
{
static Property = 10;
}
class Type1 extends Type
{
static Property = 20;
}
class Type2 extends Type
{
static Property = 30;
}
// Create a dummy interface to capture type
interface IType extends Type{}
// Use the dummy interface
function GetTypes(): IType[]
{
return [Type1, Type2];
}
GetTypes[0].Property; // Equal to 20
See it on the playground

Resources