Is it possible to define a variable with the type string and then define which possible values that string can have?
colorScheme?: string = 'positive|negative'; //must be a string
and must have the value "positive" or "negative"
Thank you.
UPDATE
It does not appear to work when defined in a component:
type ColorScheme = 'positive' | 'negative';
export class MyButtonComponent {
#Input() colorScheme?: ColorScheme;
Now it is correct. Thank you.
Yes, it's called a union type !
type ColorScheme = 'positive' | 'negative';
const scheme1: ColorScheme = 'negative'; // ok
const scheme2: ColorScheme = 'positive'; // ok
const scheme3: ColorScheme = 'foobar'; // ko
Playground
Related
Is there any way that we can define types that are checked during typescript compile time only. I want user to define a value to variable (ie not going to change on runtime) and i want to check if that value matches some criteria. For example, user need to set numeric value but cannot set less then 5, or set an string with specific format or validate with regex eg email. or string that must follow specific format or it can be pass through some condition and pass the test or else throw the error with defined message
Is there any way to achieve this in typescript??
Numeric value
You are allowed to create a union of allowed numeric values. But then you have to set maximum allowed value and compute range. See this answer and my article.
Here you have small example:
type MAXIMUM_ALLOWED_BOUNDARY = 999
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? [...Result, Result['length']][number]
: ComputeRange<N, [...Result, Result['length']]>
)
type NumberRange = ComputeRange<MAXIMUM_ALLOWED_BOUNDARY>
type Except<N extends number, CustomRange extends number> = Exclude<CustomRange, N>
type GreaterThanFive = Except<ComputeRange<5>, NumberRange>
const less: GreaterThanFive = 2 //expected error
const greater: GreaterThanFive = 6 // ok
Playground
String with specific format.
You can use template literal strings
type SpecificFormat = `${string}-${string}`
type StringDigit = `${number}`
const str: SpecificFormat = 'hello-world' // ok
const str2: SpecificFormat = 'hello world' // expected error
const strDigit: StringDigit = '42' // ok
const strDigit2: StringDigit = '42a' // expected error
However, if you want to apply more advanced restrictions, for instance check whether it is a valid HEX value or email you need to use duplicate variable value in a type or use extra dummy function. See example:
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? Result[number]
: ComputeRange<N, [...Result, Result['length']]>
)
type HexNumber = `${ComputeRange<10>}`
type HexString =
| 'A'
| 'B'
| 'C'
| 'D'
| 'E'
| 'F'
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
type Hex = `${HexNumber}` | HexString;
type StringLength<
Str extends string,
Acc extends string[] = []
> =
(Str extends `${infer S}${infer Rest}`
? StringLength<Rest, [...Acc, S]>
: Acc['length'])
type ValidateLength<
Str extends string,
Length extends number
> =
(StringLength<Str> extends Length
? Str
: never)
type WithHash<T extends string> = `#${T}`
type ValidateHex<
Color extends string,
Cache extends string = '',
> =
Color extends `${infer A}${infer Rest}`
? (A extends ''
? WithHash<Cache>
: (A extends Hex
? ValidateHex<Rest, `${Cache}${A}`>
: never)
) : WithHash<Cache>
const hex: ValidateHex<'ffffff'> = '#ffffff' // ok
const hex2: ValidateHex<'fffffz'> = '#ffffff' // expected error
Playground
If you want to validate function arguments you can check this answer, this answer or my article
If you are interested in email validation you can check this answer or my article
Also it is possible to apply restriction where all chars should be lowercased or uppercased, fir this purpose you can use built in intrinsic utility types:
// credits goes to #jcalz https://stackoverflow.com/questions/68963491/define-a-typescript-type-that-takes-a-lowercase-word#answer-73732194
let str: Lowercase<string>;
str = "abc"; // okay
str = "DEF"; // error in TS4.8+
However, it works only for TS 4.8 +. See my article or this answer
I have a business scenario which is equivalent to below tricky situation. Hence putting this problem across in a simple way as below.
File1.ts
import * from 'something';
export const var1="value of var1";
//lets say we have a variable 'x' and this needs to be exported too. However value of x is still unknown.
export const x;
File2.ts
import * from 'something';
//set the value of 'x' in File1.ts as 5
File3.ts
import * from 'something'
//I should be able to get the value of 'x' from File1.ts. But it should be equal to the value set by File2.ts which is 5
As mentioned above, I should be able to set the value of x from somewhere (in this case, File2.ts) and everytime I use 'x' from File1.ts, be it in File3.ts or any other file, the value of 'x' should be 5 (set from File2.ts)
File1.ts
var x = 99 //some unknow value
function setValueOfX(value){
x = value
}
function getValueOfX(){
return x
}
module.exports = {
setValueOfX,
getValueOfX,
}
File2.ts
const File1 = require('./File1.ts')
File1.setValueOfX(5) /// you can set the value of x using the function
File3.ts
const File1 = require('./File1.ts')
console.log(File1.getValueOfX()) /// you can get value of x by using .getValueOfX function
When creating an instance of an object, I'm having trouble setting its properties if I assign the property to another variable.
Eg. For an object containing nested objects, I want to assign one of the children to a temporary var to make it easier to work with.
Instead of doing this (which works):
myObj.myChildObject[0].someOtherChild[0].property = "something"
I'm trying to do:
var t = myObj.myChildObject[0].someOtherChild[0]
t.property = "something"
// this doesn't throw an error but doesn't change the value of myObj
What gives?
Edit>
Here's a contrived example to illustrate:
class Car { var name: String = "" }
var merc = Car()
var obj = merc.name
merc.name = "C63 AMG"
obj = "E300"
print("merc.name: \(merc.name)") // prints merc.name: C63 AMG
print("obj.name: \(obj)") // prints obj.name: E300
var ob2 = merc
ob2.name = "Toyota"
print("ob2.name: \(ob2.name)") // prints ob2.name: Toyota
print("merc.name: \(merc.name)") // prints merc.name: Toyota
So assigning the class instance to a var creates a reference. But assigning a property of that object to another var creates a copy?
I read through https://developer.apple.com/swift/blog/?id=10 and still don't get it :(
In the above, 'obj' is not a struct, enum or tuple, so shouldn't it be a reference type?
If myObj.myChildObject[0].someOtherChild[0] is a value type (I.e. a strict, direct enum or tuple), it's being copied upon assignment to t. Subsequent mutations on t only mutate that copy, and the original instance are unchanged.
You would have to reassign t back in:
var t = myObj.myChildObject[0].someOtherChild[0]
t.property = "something"
myObj.myChildObject[0].someOtherChild[0] = t
This is discussed in the Swift language guide.
I don't understand what to do with the issue reported by the compiler. I tried to create a Range, but it says Index is not known:
//let range = matches.first!.range.location
let range = Range(
start:matches.first!.range.location,
end: matches.first!.range.location+matches.first!.range.length
)
id = text[range]
var t = text
t.removeRange(range)
return t
Compiler says: Cannot invoke 'removeRange' with an argument list of type '(Range)' on t.removeRange(range).
I'm pretty sure it's evident, but I lost a great deal of time on such a small issue… any help highly appreciated!
As your error says that:
Cannot invoke 'removeRange' with an argument list of type '(Range)'
Means there is a problem with your range instance type and removeRange function will only accept an argument with type Range<String.Index> and its syntax is :
/// Remove the indicated `subRange` of characters
///
/// Invalidates all indices with respect to `self`.
///
/// Complexity: O(\ `count(self)`\ ).
mutating func removeRange(subRange: Range<String.Index>)
And here is working example with removeRange:
var welcome = "hello there"
let range = advance(welcome.endIndex, -6)..<welcome.endIndex
welcome.removeRange(range)
println(welcome) //hello
Hope this will help.
Swift 2.2 example of removing first 4 characters:
let range = text.startIndex..<text.startIndex.advancedBy(4)
text.removeRange(range)
That first line feels verbose. I hope newer Swift versions improve upon it.
Here is the working equivalent snippet:
static func unitTest() {
let text = "a👿bbbbb🇩🇪c"
let tag = Tag(id: "🇩🇪")
tag.regex = "👿b+"
print ("Unit test tag.foundIn(\(text)) ? = \(tag.foundIn(text))")
}
func foundIn(text: String) -> (id:String, remainingText:String)? {
// if a regex is provided, use it to capture, and keep the capture as a tag ID
if let regex = regex {
let r = Regex(regex) // text =~ regex
let matches = r.matches(text)
if matches.count >= 1 {
let first = matches.first!.range
let start = advance(text.startIndex, first.location)
let end = advance(start, first.length-1)
let range = Range(start: start, end: end)
id = text[range]
var t = text
t.removeRange(range)
return (id, t)
}
return nil
}
else if let range = text.rangeOfString(id) {
var t = text
t.removeRange(range)
return (id, t)
}
else {
return nil
}
}
The unit test returns :
Unit test tag.foundIn(a👿bbbbb🇩🇪c) ? = Optional(("👿bbbbb", "a🇩🇪c"))
How do I remove Optional Character
let color = colorChoiceSegmentedControl.titleForSegmentAtIndex(colorChoiceSegmentedControl.selectedSegmentIndex)
println(color) // Optional("Red")
let imageURLString = "http://hahaha.com/ha.php?color=\(color)"
println(imageURLString)
//http://hahaha.com/ha.php?color=Optional("Red")
I just want output "http://hahaha.com/ha.php?color=Red"
How can I do?
hmm....
Actually when you define any variable as a optional then you need to unwrap that optional value. To fix this problem either you have to declare variable as non option or put !(exclamation) mark behind the variable to unwrap the option value.
var optionalVariable : String? // This is an optional.
optionalVariable = "I am a programer"
print(optionalVariable) // Optional("I am a programer")
var nonOptionalVariable : String // This is not optional.
nonOptionalVariable = "I am a programer"
print(nonOptionalVariable) // "I am a programer"
//There are different ways to unwrap optional varialble
// 1 (Using if let or if var)
if let optionalVariable1 = optionalVariable {
print(optionalVariable1)
}
// 2 (Using guard let or guard var)
guard let optionalVariable2 = optionalVariable else {
fatalError()
}
print(optionalVariable2)
// 3 (Using default value ?? )
print(optionalVariable ?? "default value") // If variable is empty it will return default value
// 4 (Using force caste !)
print(optionalVariable!) // This is unsafe way and may lead to crash
I looked over this again and i'm simplifying my answer. I think most the answers here are missing the point. You usually want to print whether or not your variable has a value and you also want your program not to crash if it doesn't (so don't use !). Here just do this
print("color: \(color ?? "")")
This will give you blank or the value.
You need to unwrap the optional before you try to use it via string interpolation. The safest way to do that is via optional binding:
if let color = colorChoiceSegmentedControl.titleForSegmentAtIndex(colorChoiceSegmentedControl.selectedSegmentIndex) {
println(color) // "Red"
let imageURLString = "http://hahaha.com/ha.php?color=\(color)"
println(imageURLString) // http://hahaha.com/ha.php?color=Red
}
In swift3 you can easily remove optional
if let value = optionalvariable{
//in value you will get non optional value
}
Check for nil and unwrap using "!":
let color = colorChoiceSegmentedControl.titleForSegmentAtIndex(colorChoiceSegmentedControl.selectedSegmentIndex)
println(color) // Optional("Red")
if color != nil {
println(color!) // "Red"
let imageURLString = "http://hahaha.com/ha.php?color=\(color!)"
println(imageURLString)
//"http://hahaha.com/ha.php?color=Red"
}
Besides the solutions mentioned in other answers, if you want to always avoid that Optional text for your whole project, you can add this pod:
pod 'NoOptionalInterpolation'
(https://github.com/T-Pham/NoOptionalInterpolation)
The pod adds an extension to override the string interpolation init method to get rid of the Optional text once for all. It also provides a custom operator * to bring the default behaviour back.
So:
import NoOptionalInterpolation
let a: String? = "string"
"\(a)" // string
"\(a*)" // Optional("string")
Please see this answer https://stackoverflow.com/a/37481627/6390582 for more details.
Try this,
var check:String?="optional String"
print(check!) //optional string. This will result in nil while unwrapping an optional value if value is not initialized or if initialized to nil.
print(check) //Optional("optional string") //nil values are handled in this statement
Go with first if you are confident to have no nil in your variable.
Also, you can use if let or Guard let statement to unwrap optionals without any crash.
if let unwrapperStr = check
{
print(unwrapperStr) //optional String
}
Guard let,
guard let gUnwrap = check else
{
//handle failed unwrap case here
}
print(gUnwrap) //optional String
Simple convert ? to ! fixed my issue:
usernameLabel.text = "\(userInfo?.userName)"
To
usernameLabel.text = "\(userInfo!.userName)"
Although we might have different contexts, the below worked for me.
I wrapped every part of my variable in brackets and then added an exclamation mark outside the right closing bracket.
For example, print(documentData["mileage"]) is changed to:
print((documentData["mileage"])!)
import UIKit
let characters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
var a: String = characters.randomElement()!
var b: String = characters.randomElement()!
var c: String = characters.randomElement()!
var d: String = characters.randomElement()!
var e: String = characters.randomElement()!
var f: String = characters.randomElement()!
var password = ("\(a)" + "\(b)" + "\(c)" + "\(d)" + "\(e)" + "\(f)")
print ( password)
when you define any variable as a optional then you need to unwrap that optional value.Convert ? to !
How do I remove optional String Character for Printing in Swift UIkit
From These (Have Optional printing)
print("Collection Cell \(categories[indexPath.row].title) \(indexPath.row)")
To these ( Doesn't have Optional printing)
print("Collection Cell \(categories[indexPath.row].title ?? "default value") \(indexPath.row)")
print("imageURLString = " + imageURLString!)
just use !
You can just put ! and it will work:
print(var1) // optional("something")
print(var1!) // "something"