Use display: inline-block
to make sure they're visible.
To place an icon in an input field, it can be set as the background-image
.
.icon::after {
background-image: url(../../assets/chevron-down.svg);
content: "";
display: inline-block;
position: absolute;
right: 16px;
bottom: 16px;
}
To include node modules in VSCode search add this to settings.json
:
"search.exclude": {
"**/node_modules": false
},
"search.useIgnoreFiles": false
function identity<T>(arg: T): T {
return arg;
}
After the name of the function we have included a type variable, T, in angled brackets <>. T is now a placeholder for the type we wish to pass into identity, and is assigned to arg in place of its type: instead of number, T is now acting as the type.
We are not limited to only one type variable.
function identities<T, U>(arg1: T, arg2: U): T {
return arg1;
}
Now we have an identities()
function that supports two generic types, with the addition of the U type variable — but the return type remains T. Our function is now clever enough to adopt two types, and return the same type as our arg1 parameter.
interface Identities<V, W> {
id1: V,
id2: W
}
We can now apply this interface as the return type of identities(), amending our return type to adhere to it.
function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
let identities: Identities<T, U> = {
id1: arg1,
id2: arg2
};
return identities;
}
class Programmer<T> {
private languageName: string;
private languageInfo: T;
constructor(lang: string) {
this.languageName = lang;
}
...
}
let programmer1 =
new Programmer<Language.Typescript>("Typescript");
let programmer2 =
new Programmer<Language.Rust>("Rust");
For our Programmer class, T is a type variable for programming language meta data, allowing us to assign various language types to the languageInfo property. Every language will inevitably have different metadata, and therefore need a different type.
For instantiating classes, there is not much the compiler can do to guess which language type we want assigned to our programmer; it is compulsory to pass the type here. However, with functions, the compiler can guess which type we want our generics to be — and this is the most common way developers opt to use generics.
// this will cause an error
function identity<T>(arg: T): T {
console.log(arg.length);
return arg;
}
What we need to do is extend our type variable to an interface that houses our required properties.
interface Length {
length: number;
}
function identity<T extends Length>(arg: T): T {
// length property can now be called
console.log(arg.length);
return arg;
}
This is how we say: "Whatever type T is, it must contain the properties in Length otherwise the compiler will warn us when calling the function that the argument passed is either not of shape object or the object does not contain the property length".
interface Foo {
bar: number;
bas: string;
}
var foo = {} as Foo; // here the compiler won't tell you anything is wrong even though bar and bas are missing!!
Unfortunately you can not use typescript optional “?” to define a variable as potentially undefined or a function return type as undefined and you might want an abstraction to cover this.
type Optional<T> = T | undefined
This way if your user might not be here because it is loading for example while you first render your components, you could have a user with the following type:
let user: Optional<User>;
Which is going to be the same as defining the following type:
let user: User | undefined;
useEffect watches for changes in the elements passed in the optional array as the second arguments. If the array is empty it won't watch for any changes.
useEffect(() => {
console.log("componentDidMount");
};
}, []); // empty-array means don't watch for any updates
data: Array<Car | Plane> // data can contain either Plane or Car
data: Plane[] | Car[] // data can be either of type Plane or type Car but not both --> more strict
type Car = {
brand: string;
}
type Plane = {
year: number;
}
function add(arg: Plane | Car) {
if ('brand' in arg) {
arg // car
} else {
arg // plane
}
}
Example can be used to test which type we have.
function extend<First, Second>(first: First, second: Second): First & Second {
const result: Partial<First & Second> = {};
for (const prop in first) {
if (first.hasOwnProperty(prop)) {
(result as First)[prop] = first[prop];
}
}
for (const prop in second) {
if (second.hasOwnProperty(prop)) {
(result as Second)[prop] = second[prop];
}
}
return result as First & Second;
}
Function extend
takes arguments of type First
and Second
and returns either of types First
or Second
.
result
initially is an empty object that can contain properties from First
or Seconds
but can also have nothing (neither a prop from First
or Second
).
The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as its own property (as opposed to inheriting it).
Upon looping over the objects, if the key prop
exists in the type and is not inherited, add the key value pair to the results
object as that type.
Finally return an object containing properties from both type First
and Second
.
Sources: TS Advanced Types & mdn hasOwnProperty
interface FileReformatted {
extension: string;
name: string;
}
class FileModel {
fileFormatted: Record<string, FileReformatted> = {}
}
const file = new FileModel
file.fileFormatted
One of the popular cases when Record works in well is an interface for a business entity that you keep in a dictionary as key-value pairs.
Partial type makes all properties in the object optional.
https://levelup.gitconnected.com/advanced-typescript-types-with-examples-1d144e4eda9e
const cities = ['Basel', 'Zurich', 'Zurich', 'Bern']
let uniqueCities = [...new Set(cities)] // ['Basel', 'Zurich', 'Bern']
Why compound commponents are useful:
- Internally they are built to operate on a set of data that is passed in through
children
instead ofprops
- They provide a way to shield feature specific logic from the rest of the app providing a clean and expressive API for consuming the component
From acticle: React.js — Compound Components