Using Extract, Generic T extends to control designated properties of Unioned classes (typescript)
ref – https://stackoverflow.com/questions/56067863/discriminating-a-union-of-classes
We declare abstract class Fruit, which says any class that extends this MUST declare readonly property fruitType of type string.
1 2 3 |
abstract class Fruit { abstract readonly fruitType: string; } |
So we create Banana, which extends Fruity. We must declare property readonly fruitType and initialize it with string banana
We also give it unique properties length and color.
1 2 3 4 5 6 7 |
class Banana extends Fruit { readonly fruitType = 'banana'; // required from Fruit // unique attributes length = 2; color = 'yellow'; } |
We do this same for Pear and Apple, and give them their own unique characteristics. But they all must have property readonly fruitType of type string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Pear extends Fruit { readonly fruitType = 'pear'; // required from Fruit // unique attributes roundness = 'very round'; } class Apple extends Fruit { readonly fruitType = 'apple'; // required from Fruit // unique attributes fallOfMan = true; hasWorms = true; } |
Then, we create a Union of class types called KnownFruits. KnownFruits is a Union of class Banana, Pear, and Apple. Basically we’re grouping them together. KnownFruits is the group fruits I want to select from later.
1 2 3 4 5 6 7 8 |
type KnownFruits = Banana | Pear | Apple; const aa: KnownFruits = new Banana(); // ok const bb: KnownFruits = new Pear(); // ok const cc: KnownFruits = new Apple(); // ok class Hahah {} const bb: KnownFruits = new Haha(); // error |
So we know that KnownFruits type restricts the type that it can reference into the group that consists of Banana, Pear, and Apple.
Now let’s get a union of its keys. We basically get the group of keys by giving the property name ‘fruitType’ to the group (Union) of class types like so:
1 2 3 4 5 6 |
type FruitTypes = KnownFruits['fruitType']; // "banana" | "pear" | "apple" const a: FruitTypes = 'apple'; // ok const b: FruitTypes = 'banana'; // ok const c: FruitTypes = 'pear'; // ok // const z: FruitTypes = 'zoo'; // Type '"zoo"' is not assignable to type '"banana" | "pear" | "apple"'. |
Extracting the wanted class by using key string
we declare a type called FruitDiscriminator
1 |
type FruitDiscriminator |
This type consists of generic T where it extends from FruitTypes. When generic T extends from FruitTypes this means, it means
whatever object T you pass in must be ‘apple’ OR ‘banana’ OR ‘pear’.
1 |
type FruitDiscriminator<T extends FruitTypes> |
So when we pass in this object, it must contain a property called fruitType that is of type union FruitTypes.
In other words, T extends FruitTypes means we restrict generic class to MUST BE FruitTypes, which is “banana” | “pear” | “apple”
So if we put in ‘pineapple’ for fruitType, it will get error.
1 |
type FruitDiscriminator<T extends FruitTypes> = (someFunction or class)<{ fruitType: T }>; |
Now, the functionality or class we want to use is called Extract.
We Extract the class we want from the union of our classes (KnownFruits), by using property fruitType. As mentioned above, property fruitType must be of type FruitTypes.
Extract simply takes the fruitType (say ‘apple’), and then extract the class type from union KnownFruits. In our case of ‘apple’, it will extract Apple.
1 |
type FruitDiscriminator<T extends FruitTypes> = Extract<KnownFruits, { fruitType: T }>; |
Assignment example
So let’s try it out with a basic example.
1 2 |
const test: FruitDiscriminator<'pineapple'> = { } |
Type ‘”pineapple”‘ does not satisfy the constraint ‘”banana” | “pear” | “apple”‘.(2344)
So let’s use a string that satisfies union FruitTypes.
1 2 |
const test: FruitDiscriminator<'banana'> = { } |
Great it worked, but we see another error here. Type ‘{}’ is missing the following properties from type ‘Banana’: fruitType, length, color(2739)
So because ‘banana’ will return us the class type Banana, we must fill in the missing properties length and color.
So now, the error goes away. Notice also that FruitDiscriminator’s generic type T forces fruitType to have the same string of ‘banana’.
1 2 3 4 5 |
const test: FruitDiscriminator<'banana'> = { fruitType: 'banana', length: 3, color: 'brownish' } |
Function example
Now we create a function called createFruit. It takes in two parameters. The firstone is fruitType, which is of type generic T, that extends from FruitTypes. Ok so it is union “banana” | “pear” | “apple”.
Then we have props, which is FruitDiscriminator of the same generic T.
1 2 3 4 5 6 7 8 9 10 |
type FruitDiscriminator = Extract<KnownFruits, { fruitType: FruitTypes }>; let createFruit =(props: FruitDiscriminator) => { // code } createFruit({ fruitType: 'banana', length: 3, color: 'moorish', }); |
or using generics:
1 2 3 4 5 6 7 8 9 10 |
type FruitDiscriminator<T> = Extract<KnownFruits, { fruitType: T}>; let createFruit = <T extends FruitTypes>(props: FruitDiscriminator<T>) => { // code } createFruit({ fruitType: 'banana', length: 3, color: 'moorish', }); |
Mapped Types (typescript)
ref – https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
1 2 3 4 5 6 7 8 9 10 11 |
// we declare a type called OnlyBoolsAndHorses type OnlyBoolsAndHorses = { // for all keys, it must be boolean or number [key: string]: boolean | number; }; // example: const conforms: OnlyBoolsAndHorses = { del: true, rodney: 2534 } |
declare a type called AllAreBooleanProperties that takes in a type object called Type.
Then for every property in object Type, declare it to be boolean.
1 2 3 |
type AllAreBooleanProperties<Type> = { [Property in keyof Type]: boolean; }; |
Example usage, say we have an object type that has properties type () => void:
1 2 3 4 |
type FeatureFlags = { darkMode: () => void; newUserProfile: () => void; }; |
now we use our AllAreBooleanProperties type generator and create a type that says all properties must be boolean:
1 |
type FeatureOptions = AllAreBooleanProperties<FeatureFlags>; |
Thus creating a type that forces object type to have all boolean properties.
1 2 3 4 |
const tmp: FeatureOptions = { darkMode: true, newUserProfile: false } |
mqtt qos
ref-
http://www.steves-internet-guide.com/understanding-mqtt-qos-1/
The QOS levels are a way of guaranteeing message delivery and they refer to the connection between a broker and a client.
In this two part tutorial we will look in detail at the message flow when publishing using all three QOS levels.
We also look at the advantages and disadvantages of using the various levels
QOS 0 – Once
This is the fastest method and requires only 1 message. It is also the most unreliable transfer mode.
The message is not stored on the sender, and is not acknowledged.
The message will be delivered only once, or not at all.
Once the message has been sent by the client it is deleted from the outbound message queue.
Therefore with this QOS level there is no possibility of duplicate messages.
QOS 1 – At Least Once
This level guarantees that the message will be delivered at least once, but may be delivered more than once.
Publishing with QOS of 1 requires 2 messages.
The sender sends a message and waits for an acknowledgement (PUBACK).
If it receives an acknowledgement then it notifies the client app, (thus the callback) and deletes the message from the outbound queue..
If it doesn’t receive an acknowledgement it will resend the message with the DUP flag set (Duplicate Flag).
The message will continue to be resent at regular intervals, until the sender receives an acknowledgement.
If the message is being sent to the broker then the broker will forward that message to subscribers even though the duplicate flag is set.
Therefore subscribers can receive the same message multiple times.
QOS 2 – Only Once
This level guarantees that the message will be delivered only once. You keep them in line by messageId.
This is the slowest method as it requires 4 messages.
1- The sender sends a message and waits for an acknowledgement (PUBREC)
2 -The receiver sends a PUBREC message
3. If the sender doesn’t receive an acknowledgement ( PUBREC) it will resend the message with the DUP flag set.
4. When the sender receives an acknowledgement message PUBREC it then sends a message release message (PUBREL). The message can be deleted from the queue.
5. If the receiver doesn’t receive the PUBREL it will resend the PUBREC message
5. When the receiver receives the PUBREL message it can now forward the message onto any subscribers.
6. The receiver then send a publish complete (PUBCOMP) .
7. If the sender doesn’t receive the PUBCOMP message it will resend the PUBREL message.
8. When the sender receives the PUBCOMP the process is complete and it can delete the message from the outbound queue, and also the message state.
useFocusEffect vs useEffect
useFocusEffect
By defintion:
1 |
function useFocusEffect(effect: EffectCallback): void; |
It just has an effect to run.
For useFocusEffect, when you hit the current page, it runs the effect, and caches the cleanup.
When you go to the next page, it’ll execute the next page’s effect first. And then runs the clean up of the previous page.
So in our case
when we hit Page1, execute effect Page 1 (A).
Goes to page 2, execute effect page 2 (K), clean up Page 1 (Z)
Goes to page 3, execute effect page 3 (M), clean up Page 2 (R)
From page 3 back to page 2, clean up Page 3 (N), execute effect Page 2 (K)
From page 2 back to page 1, clean up Page 2 (R), execute effect Page 1 (A)
A huge difference is that useFocusEffect does not have a dependency list, which it depends on for it to run its cleanup/effect.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
import React, { useEffect } from 'react'; import { Button, View } from 'react-native'; import { NavigationContainer, useNavigation, useFocusEffect, } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; const Page1 = () => { const { navigate } = useNavigation(); useFocusEffect(() => { console.log('A'); return () => { console.log('Z'); }; }); return ( <View> <Button onPress={() => navigate('PAGE2')} title="Go to Page2" /> </View> ); }; const Page2 = () => { const { navigate } = useNavigation(); useFocusEffect(() => { console.log('K'); return () => { console.log('R'); }; }); return ( <View> <Button onPress={() => navigate('PAGE3')} title="Go to Page3" /> </View> ); }; const Page3 = () => { useFocusEffect(() => { console.log('M'); return () => { console.log('N'); }; }); return null; }; const Stack = createStackNavigator(); const App = () => { return ( <NavigationContainer> <Stack.Navigator initialRouteName="PAGE1"> <Stack.Screen name="PAGE1" component={Page1} /> <Stack.Screen name="PAGE2" component={Page2} /> <Stack.Screen name="PAGE3" component={Page3} /> </Stack.Navigator> </NavigationContainer> ); }; export default App; |
useEffect
Whereas for useEffect, we also have an effect and cleanup, but they depend on the dependency list’s variables changing.
If it changes, then we’ll run the clean up, and then the effect.
If nothing changes in the variables, then we do nothing!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import React, { useEffect, useState } from 'react'; import { Button, View } from 'react-native'; import { NavigationContainer, } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; const Page1 = () => { const [b, setB] = useState(false); useEffect(() => { console.log('sign you in!'); return () => console.log('sign you out!'); }, [b]) return ( <View> <Button onPress={() => setB(!b)} title="push me" /> </View> ); }; const Stack = createStackNavigator(); const App = () => { return ( <NavigationContainer> <Stack.Navigator initialRouteName="PAGE1"> <Stack.Screen name="PAGE1" component={Page1} /> </Stack.Navigator> </NavigationContainer> ); }; export default App; |
mqtt keep alive
KeepAlive
The keep alive is a time interval in seconds that the client specifies and communicates to the broker when the connection established. This interval defines the longest period of time that the broker and client can endure without sending a message. The client commits to sending regular PING Request messages to the broker. The broker responds with a PING response. This method allows both sides to determine if the other one is still available. See part 10 of this series for detailed information about the MQTT keep alive functionality.
Basically, that is all the information that is all you need to connect to an MQTT broker from an MQTT 3.1.1 client. Individual libraries often have additional options that you can configure. For example, the way that queued messages are stored in a specific implementation.
Combining types and test for it in typescript
Let’s combine some types and test for them:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
type Item = { item: string, index: number } type Another = Item & { isVisible: boolean } const test: Another = { item: "heh", index: 3, isVisible: true } type Receipt = { total: number, id: string } const isItem = (info: Receipt | Item): boolean => { let res = (info as Item).item !== undefined; return res; } const a: Item = { item: "driver", index: 3 } const b: Another = { item: "screw", index: 8, isVisible: false } const c: Receipt = { total: 2434, id: "FJSK2SJ242" } console.log(isItem(a)); // true console.log(isItem(b)); // true console.log(isItem(c)); // false |
Command PhaseScriptExecution failed with a nonzero exit code
ref – https://developer.apple.com/forums/thread/123790
I usually have this problem when a dependency is not updated.
Delete your Podfile.lock (I like to use the command ‘-rm -rf Podfile.lock’ on the terminal for this)
Delete your Pods folder (I like to use the command ‘-rm -rf Pods’ in the terminal for this)
Pod install
Clear your project in XCode > Product > Clean Build Folder
Remove Listeners when you are done with them
If you don’t remove listeners on dismount, it will cause memory leaks and potential crashes.
1 2 3 4 5 6 7 8 9 |
useEffect(() => { const listener = DeviceEventEmitter.addListener('DoSomething', ({id}: {id: number}) => { // code }); return () => { listener.remove(); }; }); |
cloneElement (React)
https://www.geeksforgeeks.org/how-to-use-react-cloneelement-function/