Complex Types in Typescript, React [duplicate] - reactjs

This question already has answers here:
How to define a regex-matched string type in Typescript?
(9 answers)
Closed 2 years ago.
I am wondering if there is a way to create types that are verified by a function in Typescript/React.
Instead of a 'string' type for example, I would like it to be a regex expression:
interface Verify
{
email: /.+#.*\.com/g;
}
The regex may not work but the concept is of a prop type being a string matching the regex.
A more generalized and useful is to have the input pass through a function to verify it:
interface AcceptableInput
{
input: checkIfInputIsAcceptable(input)
}
let obj: AcceptableInput = { input: "works#working.com" }
Then to check if the input is of the correct type it would check with a function:
function checkIfInputIsAcceptable(input)
{
if(typeof input === "string)
return true;
if(input instanceof AnotherInterface)
return true;
return false;
}
The code does not work, but I hope it exemplifies the concept I am asking about.
I am not sure if this is possible. Any workarounds would also be appreciated.

TypeScript won't really do any complex validation because it's fairly pointless (because you can solve the same issue in different ways, see below) and it heavily complicates the type system. The best way to do something like this is probably via type guards and runtime validation code. (see https://www.typescriptlang.org/docs/handbook/advanced-types.html)
If you're matching against a very basic string pattern then you could also consider looking into template literal types which were added in Typescript 4.1 (see https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html)

Related

Check if generic is an array with inline function

How can I check if a Generic is an Array using an inline function?
I tried with the following code:
class Mediator {
inline fun <reified C> mediate(string: String): Container<C> {
if (C::class == Int::class) {
//It works
}
else if (C::class == Array::class) {
//It doesn't work!
}
throw IllegalStateException("Yopta")
}
}
But it doesn't work. Maybe because it can be Array<Whatever>?
How can I do it?
Contrary to collections where for example List<String> and List<Int> are internally represented by the same class List, in arrays the type parameter is a part of the type itself. That means Array<String> and Array<Int> are internally represented as different types and as far as I know, they don't have a common super type.
I don't know a pure Kotlin solution to check if a class is an array. It seems to me like an overlook in the design of the reflection API. If you don't mind using the Java reflection, you can do it like this:
else if (C::class.java.isArray) {
Update
There is one interesting fact here. In the Kotlin type system we could consider Array<out Any?> to be a supertype of all arrays. For example, we can upcast to it without an explicit cast operator:
val intArray = arrayOf(1, 2, 3)
val arr: Array<out Any?> = intArray
However, for the reflection API these two types are entirely different:
// false
println(Array<Int>::class.isSubclassOf(Array<out Any?>::class))
I assume this is due to how arrays where implemented in Java. I'm not even sure if it would be technically possible to return true in the code above. Still, it is concerning it provides a different result than the type system at a compile time and it doesn't even produce a warning.
Actual answer that solves the issue here.
Since broot added an actual answer I'll just leave this here as a note as to how we can see that he is right basically.
If we make the call like this:
Mediator().mediate<Array<Int>>("")
Adding a simple check inside the function like this makes it a bit confusing as to why they are not equal.
println(C::class) //class Kotlin.Array
println(Array:class) //class Kotlin.Array
But doing the same for the underlying java class shows that they are not really the same object.
println(C::class.java) //class [Ljava.lang.Integer
println(Array:class.java) //class [Ljava.lang.Object
So changing the statement to:
if(C::class.java == Array<Int>::class.java)
Will make the example work ... for Int only. All other "infinite" possibilities will have to be added manually. Not an issue if you just want to check Array<X> only, but definitely not generic.

What problem does the Kleisli arrows solve in fp-ts?

I'm learning functional programming by using fp-ts lib and noticed that some functions end with K, like:
chainTaskEitherK
chainEitherK
fromTaskK
Also I read the explanation of What a K suffix means in fp-ts documentation, but unfortunately I can't say that one example gives me a solid idea of how to use it on the battlefield.
I would like to know exactly what problem they solve and what the code would look like without them (to see the benefit).
Please, consider that I'm a newbie in this topic.
First, (going off of the example in the link you shared). I think a Kleisli arrow is just a name for a type that looks like:
<A>(value: A) => F<A>
where F is some Functor value. They call it a constructor in the doc you linked which might be more precise? My understanding is that it's just a function that takes some non-Functor value (a string in the parse example) and puts it into some Functor.
These helpers you've listed are there for when you already have a Kleisli arrow and you want to use it with some other Functor values. In the example they have
declare function parse(s: string): Either<Error, number>;
and they have an IOEither value that would probably come from user input. They want to combine the two, basically run parse on the input if it's a Right and end up with a function using parse with the signature:
declare function parseForIO(s: string): IOEither<Error, number>;
This is so the return type can be compatible with our input type (so we can use chain on the IOEither to compose our larger function).
fromEitherK is therefore, wrapping the base parse function in some logic to naturally transform the resulting regular Either into an IOEither. The chainEitherK does that and a chain to save some of the boilerplate.
Basically, it's solving a compatibility issue when the return value from your Kleisli arrows doesn't match the value you need when chaining things together.
In addition to the #Souperman explanation I want to share my investigation on this topic
Let's take already known example from the fp-ts documentation.
We have an input variable of type IOEtiher
const input: IE.IOEither<Error, string> = IE.right('foo')
and function, which take a plain string and returns E.Either
function parse(s: string): E.Either<Error, number> {
// implentation
}
If we want to make this code works together in a fp-ts style, we need to introduce a pipe. pipe is a function which passes our data through the functions listed inside the pipe.
So, instead of doing this (imperative style)
const input: IE.IOEither<Error, string> = IE.right('foo')
const value = input()
let result: E.Either<Error, number>
if (value._tag === 'Right') {
result = parse(value.right) // where value.right is our 'foo'
}
We can do this
pipe(
input,
IE.chain(inputValue => parse(inputValue))
~~~~~~~~~~~~~~~~~ <- Error is shown
)
Error message
Type 'Either<Error, number>' is not assignable to type 'IOEither<Error, unknown>'.
Unfortunately, fp-ts cannot implicitly jump between types (e.g. from IOEither to Either) . In our example, we started with input variable which has IOEither (IE shortened) type and continue with a IE.chain method which tries to return Either value.
To make it work we can introduce a function which helps us to convert this types.
pipe(
input,
IE.chain(inputValue => IE.fromEitherK(parse)(inputValue))
)
Now our chain function explicitly know that parse function was converted from Either type to IOEither by using fromEitherK.
At this moment we can see that fromEitherK is a helper function that expects a Kleisli function in its arguments and return the new function with a new return type.
To make it more clear, we needn't to use a K suffix if, for example, our parse was a value (instead of function).
The code would look like
pipe(
input,
IE.chain(inputValue => IE.fromEither(parsed)) // I know this is useless code, but it shows its purpose
)
Returning back to our example. We can improve the code to make it more readable
Instead of this
pipe(
input,
IE.chain(inputValue => IE.fromEitherK(parse)(inputValue))
)
We can do this
pipe(
input,
IE.chain(IE.fromEitherK(parse))
)
And even more
pipe(
input,
IE.chainEitherK(parse)
)
Summary
As far I understand, a Kleisli arrows are the functions which take an argument and return a result wrapped in a container (like parse function).

Declaration of array in TypeScript [duplicate]

This question already has an answer here:
What type is [boolean]?
(1 answer)
Closed 5 years ago.
I have some experience with TypeScript, but one thing just keeps playing on my mind. I know the difference between Array<string> and string[]. I know that the declarations can be used interchangeably, f.e.
export class SomeClass {
someDeclaration: Array<SomeObject>;
otherDeclaration: SomeObject[];
}
But in my work, I faced other declaration structure, namely:
export class OtherClass {
strangeDeclaration: [SomeObject];
}
My question is: Is it correct way to declaring array? Which difference is beetwen this way and other (most popoular) ways? Where does the structure come from?
TypeScript arrays can be written Array<T> or T[] as you suggested.
The other type is a "Tuple". In TS this translated to a index typed array.
E.g. it's a array with a fixed type at the given position.
Example 'tuple array': [Number, String]
Ts Docs explains this very well

use of any in typescript

I have an angular 1.4 project on typescript, the project is getting bigger and bigger and our team is really tired of interfaces that we have declared (so that all objects are typed, in comparison to any)
I'm asking if this is a good idea or not? I chose typescript because I wanted to have a typed project, should I drop the interfaces or not?
You can get by without using interfaces and going with any, but in the long term you are probably going to regret it. If your team is sick of the interfaces you've created, I would put time in fixing those instead of abandoning them. There is a significant argument around if typed languages reduce the number of errors found in code. Personally, I think they do.
What I've found with typed languages is that it helps remove stupid mistakes we all make, and this clears up our time to focus on actual logic problems in code. Not everyone agrees with me on this, but I will always pick a type language over a non typed one, especially if the team is used to dealing with languages like Java or C#.
Interfaces can be very helpful if used properly.
If you are just doing this....
IFoo { ... }
Foo implements IFoo { ... }
Then they will not help as much as they do in other typed languages (C#/Java). Because the type checking in TypeScript is dependent upon the properties on the object and NOT on the declared type. This is because you can simply write this...
MyCtrl (foo: Foo) { ... }
//instead of
MyCtrl {foo: IFoo) { ... }
This will not hinder unit testing in any way since as stated above the type checking is based upon properties and not declarations.
There are cases when interfaces can be quite helpful, for instance a common use case is when defining an object as a parameter...
doSomething (options: ISomethingOptions) { ... }
There is no harm in creating interfaces for everything, you just need to determine what level of typing works best for your team.

Querystring with int variables vs ===

In our current project we started using angularjs.
We're facing the choice to either use == rather then === everywhere or specifically parse query parameters to their respective correct type.
Hypothetical example:
//someurl.com/search?filter=astring&sortColumn=2
$scope.filter = $location.search().filter;
$scope.sortColumn = $location.search().sortColumn;
if($scope.sortColumn === 2){
doStuff();
}
Because sortColumn comes out of the querystring as a string, the strict equation fails.
I think it comes down to either use non-strict equation or parse strings to ints.
Currently we have a stringToInt() that uses parseInt() with some extra checks on null and undefined, but this feels like we're trying to write C# in js to me.
Can we get ints from search() somehow?
Or should we switch to non-strict in our equations?
Or is there another way we didn't think of?

Resources