Inferring the type of a constant array - typescript-generics

Consider the following:
type ArrayOf<T> = T extends (infer R)[] ? R : never;
const a = ['a', 'b'];
type A = ArrayOf<typeof a>;
Type A is a synonym of string, which is what I want.
But:
type ArrayOf<T> = T extends (infer R)[] ? R : never;
const a = ['a', 'b'] as const;
type A = ArrayOf<typeof a>;
make the type A a synonym of... never, which is not what I want. I want it to be 'a' | 'b'.
Can this be done?

['a', 'b'] as const is of type readonly ['a', 'b'], which does not extend T[], but does extend readonly T[]. The difference is that a readonly T[] does not have methods that allow you to mutate the array (like push).
The correct definition of ArrayOf<T> is
type ArrayOf<T> = T extends readonly (infer R)[] ? R : never;

Related

Flow. How to specify the union type depending on the function argument

Let's say we have two types and union of them:
type A = {tag: 'a'};
type B = {tag: 'b'};
type U = A | B;
And function, which returns A or B, depending on provided tag:
const getSpecificObj = (tag: string) => U;
How can I specify that returning type? So then I will be able to use it like:
const a: A = getSpecificObj('a');
P.S. Yes, I know that I can write the same function for every type or override. But maybe there are another ways. For example in TS I can write:
type Extract<A, T> = A extends { tag: T } ? A : never;
<T>(tag: T): Extract<U, T>
Rather than returning a union of the types A and B, you need to parameterize the function getSpecificObj by the type of its argument, and then return an object which references that type parameter. Here's how I would do it:
type A = {tag: 'a'};
type B = {tag: 'b'};
function getSpecificObj<T : string>(tag: T) : { tag: T } {
return { tag };
}
const a : A = getSpecificObj('a');
const b : B = getSpecificObj('b');
The annotation <T : string> on getSpecificObj makes sure the function isn't more general than you need, and will only accept strings as tags. You can think of this as moving the string annotation off of the tag parameter and into the generic type of the tag parameter.
You can view the example on the try-flow page here.

Get the class of nullable type

I am trying to match the type of the nullable String? in a Kotlin reflection exercise:
data class Test(a: String, b: String?)
val test = Test("1", "2")
val properties = test::class.declaredMemberProperties
val propertyNames = properties.joinToString(",") {
when (it.returnType) {
String?::class.createType() -> "string?"
String::class.createType() -> "string"
else -> throw Exception()
}
}
Alas, it is failing with the error, Type in a class literal must not be nullable, for String?::class.
The createType function has an optional nullable parameter that seemed to work when I tested it.
import kotlin.reflect.full.*
String::class.createType(nullable = true) -> "string?"

Typing object of functions with flowtype

I understand that this is the type of an object, which keys are the two strings 'foo' and 'bar', and the values two functions (although I find the syntax strange):
type Func0 = {
foo(number) : number,
bar(string) : string
};
for example:
const f: Func0 = {
foo: x => 2*x,
bar: x => `hello ${x}`
};
But what is this type? The type of an object with two functions as values? If so, what are the keys?
type Func1 = {
(number) : number,
(string) : string
}
Yes, this is the callable object with two possible strict outcomes. Repro example here - try flow.
In brief,
type fn = {
(number): number,
(string): string
}
in pseudo-code is:
type fn =
(number) => number
OR
(string) => string
so:
fn(number): number
fn(string): string
While with default function declaration you cannot keep the relation between parameter type and return type:
type fn = (number | string) => number | string
in pseudo-code is:
type fn = (number OR string) => number OR string
so:
fn(number): number | string
fn(string): number | string

How to change a member field with Kotlin reflection?

I'm porting a class from Java to Kotlin. This class declares hundreds of objects. Each object has a name property which is identical with the declared variable name of the object. Java reflection allows to use the declared name via reflection to set the object member name. Just saves one parameter in hundreds of constructors.
I try to do the same in Kotlin but can't figure out how to do the property setting. Here is some simplified test code:
import kotlin.reflect.full.companionObject
import kotlin.reflect.full.declaredMemberProperties
class MyTestObject() {
var name: String = "NotInitialized"
companion object {
val Anton = MyTestObject()
val Berta = MyTestObject()
val Caesar = MyTestObject()
}
}
fun main(args : Array<String>) {
println(MyTestObject.Anton.name) // name not yet initialized
// Initialize 'name' with the variable name of the object:
for (member in MyTestObject::class.companionObject!!.declaredMemberProperties) {
if (member.returnType.toString() == "myPackage.MyTestObject") {
println("$member: ${member.name}")
// Set 'name' property to 'member.name':
// ???
}
}
println(MyTestObject.Anton.name) // now with the initialized name
}
The ??? line is where I would like to get access to the name property of MyTestObject to set it to to member.name. I'm looking for a function similar to (member.toObject() as MyTestObject).name = member.name.
While kotlin-reflection strives to be type-safe, sometimes the type system and the inference logic are not enough to allow for the things like what you are trying to do in a type-safe way. So, you have to make unchecked casts, stating that your knowledge about the types is more than the compiler can infer.
In your case, it's enough to cast member so that you can pass the companion object instance into its .get(...) and use the result as a MyTestObject, replace the // ??? line with:
#Suppress("UNCHECKED_CAST")
(member as KProperty1<Any, MyTestObject>)
.get(MyTestObject::class.companionObject!!.objectInstance!!)
.name = member.name
If you can replace MyTestObject::class.companionObject!! with MyTestObject.Companion::class (i.e. your actual use case does not involve getting .companionObject from different classes), the unchecked cast is not needed, and you can replace the statement above with this:
(member.get(MyTestObject.Companion) as MyTestObject).name = member.name
As an alternative that does not require companion object reflection at all, you can do the same binding logic with the delegation. Implementing provideDelegate allows you to customize the logic of initializing the property, and that's where you can assign the names:
operator fun MyTestObject.provideDelegate(
thisRef: MyTestObject.Companion,
property: KProperty<*>
) = apply { name = property.name }
operator fun MyTestObject.getValue(
thisRef: MyTestObject.Companion,
property: KProperty<*>
) = this
Then declare your properties as
val Anton by MyTestObject()
val Berta by MyTestObject()
val Caesar by MyTestObject()
Here is the final test code based on hotkey's solution:
package myPackage
import kotlin.reflect.full.declaredMemberProperties
class MyTestObject() {
lateinit var name: String
companion object {
val Anton = MyTestObject()
val Berta = MyTestObject()
val Caesar = MyTestObject()
init {
for (member in MyTestObject.Companion::class.declaredMemberProperties) {
if (member.returnType.toString() == "myPackage.MyTestObject") {
(member.get(MyTestObject.Companion) as MyTestObject).name = member.name
}
}
}
}
}
fun main(args : Array<String>) {
println(MyTestObject.Anton.name)
println(MyTestObject.Caesar.name)
}

Global variables in Ocaml

I am looking for a way to define global variables in ocaml so that i can change their value inside the program. The global variable that I want to user is:
type state = {connected : bool ; currentUser : string};;
let currentstate = {connected = false ; currentUser = ""};;
How can I change the value of connected and currentUser and save the new value in the same variable currentstae for the whole program?
Either declare a mutable record type:
type state =
{ mutable connected : bool; mutable currentUser : string };;
Or declare a global reference
let currentstateref = ref { connected = false; currentUser = "" };;
(then access it with !currentstateref.connected ...)
Both do different things. Mutable fields can be mutated (e.g. state.connected <- true; ... but the record containing them stays the same value). References can be updated (they "points to" some newer value).
You need to take hours to read a lot more your Ocaml book (or its reference manual). We don't have time to teach most of it to you.
A reference is really like
type 'a ref = { mutable contents: 'a };;
but with syntactic sugar (i.e. infix functions) for dereferencing (!) and updating (:=)
type state = {connected : bool ; currentUser : string};;
let currentstate = {connected = false ; currentUser = ""};;
can be translated to :
type state = {connected : bool ref ; currentUser : string ref };;
let currentstate = {connected = ref false ; currentUser = ref ""};;
to assign value :
(currentstate.connected) := true ;;
- : unit = ()
to get value :
!(currentstate.connected) ;;
- : bool = true
you can also pattern match on its content.
read more about ref here

Resources