TypeScript is a really great language, it has a very powerful type system.
We can combine various type
operators to form complex operations and values in a maintainable way.
Keyof Type Operator
We have read about union types, the keyof
operator can also be considered a union type. It takes an object type and produces a string or numeric literal union of its keys.
type Point = { x: number; y: number };
type P = keyof Point;
// type p = keyof Point
If the type has a string
or number
index signature, keyof
will return those types instead:
type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish;
// type A = number
type Mapish = { [k: string]: boolean };
type M = keyof Mapish;
// type M = string | number
Note: In the 2nd example, M
is string
| number
— this is because JavaScript object keys are always coerced as a string which means obj[0]
is always the same as obj["0"]
.
Typeof Type Operator
The typeof operator is already famous in JavaScript which can be used like this:
// Prints "string"
console.log(typeof "Hello world");
TypeScript adds a typeof operator which can be used like this:
let s = "hello";
let n: typeof s;
// let n: string
Now typeof seems to be a straightforward operator but believe me, if you know how to use it properly, you might use it conveniently to express many patterns.
For example, let’s start by looking at the predefined type ReturnType<T>
. It takes the function type and produces its return type.
function f() {
return { x: 10, y: 3 };
}
type P = ReturnType<typeof f>;
/* type P = {
x: number;
y: number;
} */
Indexed Access Types
We can use an indexed access type to look up a specific property on another type:
type Person = { name: string; age: number};
type Age = Person["age"];
// type Age = number
Since the indexing type is itself a type, so we can use unions, keyof, or other types also:
type I1 = Person["age" | "name"];
type I1 = string | number
type I2 = Person[keyof Person];
type I2 = string | number | boolean
We can not use const variable in Index Access Types.
const nameKey= "name";
type firstName= Person[nameKey];
// Type 'key' cannot be used as an index type.
// 'key' refers to a value, but is being used as a type here. Did you mean 'typeof key'?
Conditional Types
I personally think Conditional Types are really useful. These are very similar to ternary operator. These can help to decide a lot of input decision.
type paramType<T> = T extends number ? number : string;
function numberOrString<paramType>(param: paramType): void {
console.log('numbers, string', param);
}
numberOrString(1);
numberOrString("Vikas");
The type passed in function numberOrString is number then paramType will number else string.
We can then use that conditional type to simplify our overloads down to a single function with no overloads.
let a = createLabel("typescript");
let b = createLabel(2.8);
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
throw "unimplemented";
}
We have implemented one function instead of two functions using conditional types.
The power of conditional types comes from using them with generics which is shown in the above all examples.
Mapped Types
Mapped Types are really great for reusing the other types, sometimes you need a type based on another type.
type optionsFlags<Type> = {
[Property in keyof Type]: boolean;
};
type featureFlags = {
darkMode: () => void;
newUserProfile: () => void;
};
type featureOptions = optionsFlags<featureFlags>;
Above example is a very simple perfect example, we can see optionsFlags will take all the properties from featureFlags type and convert their values to be boolean .
Mapped Types are really powerful, we can do lot of great type manipulation.
Below example checks whether the object property name consists firstname , if it contains then return true else false .
type extractFirstName<Type> = {
[Property in keyof Type]: Type[Property] extends { firstName: true } ? true : false;
};
type DBFields = {
id: { format: "incrementing" };
name: { type: string; firstName: true };
};
type objectsNeedSurName = extractFirstName<DBFields>;
Template Literal Types
Template literal types in TypeScript allow you to create a new type based on a string template, build on string literal types, these types have the ability to expand into many strings via unions.
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// type AllLocaleIDs = "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
Conclusion
By mastering the use of Type Manipulation in TypeScript, you can take your code to the next level of reusability and maintainability.
How Google Search Works Google Search is used to find information on the web, including websites, images, videos, and news. Google Search works by crawling the web. Googlebot, Google’s web crawler, visits websites and collects information about them. This information includes the website’s title, content, and links to other websites. Google then stores this information in its index.
Why single threaded NodeJS? A single threaded language means it can do only one thing at a time. Then why we use a single threaded language like NodeJS to create high traffic web applications with lots of concurrent connection. Doesn’t it look counterintuitive? Don’t you think a multi-thread language like Java and C++ will be more appropriate for this use case?