How to use generic types to get object with same type
Update: For a better solution, see Rob's answer.
Similarly as in How can I create instances of managed object subclasses in a NSManagedObject Swift extension?,
this can be done with a generic helper method:
extension NSManagedObject {
func transferTo(context context: NSManagedObjectContext) -> Self {
return transferToHelper(context: context)
}
private func transferToHelper<T>(context context: NSManagedObjectContext) -> T {
return context.objectWithID(objectID) as! T
}
}
Note that I have changed the return type to Self
.objectWithID()
does not return an optional
(in contrast to objectRegisteredForID()
, so there is no need to
return an optional here.
Update: Jean-Philippe Pellet's suggested
to define a global reusable function instead of the helper method
to cast the return value to the appropriate type.
I would suggest to define two (overloaded) versions, to make this
work with both optional and non-optional objects (without an unwanted
automatic wrapping into an optional):
func objcast<T>(obj: AnyObject) -> T {
return obj as! T
}
func objcast<T>(obj: AnyObject?) -> T? {
return obj as! T?
}
extension NSManagedObject {
func transferTo(context context: NSManagedObjectContext) -> Self {
let result = context.objectWithID(objectID) // NSManagedObject
return objcast(result) // Self
}
func transferUsingRegisteredID(context context: NSManagedObjectContext) -> Self? {
let result = context.objectRegisteredForID(objectID) // NSManagedObject?
return objcast(result) // Self?
}
}
(I have updated the code for Swift 2/Xcode 7. The code for earlier
Swift versions can be found in the edit history.)
Generic Types: Dynamically type check specific object properties: using key ~ value pair from Type A, in Generic Type B
You can generate a union for each possible key : BatchObj<"Text"> | BatchObj<"Note"> | BatchObj<"Number">
using the distribution of conditional types. This will ensure the relationship between fieldType
and properties
is preserved:
type BatchObj<K extends keyof FieldTypeProperties> = {
fieldType: K;
properties: FieldTypeProperties[K];
}
type BatchObjUnion<K extends keyof FieldTypeProperties = keyof FieldTypeProperties> = K extends K ? BatchObj<K>: never
// Intended Usage:
let testBatch1: BatchObjUnion[] = [
{
fieldType: supportedFields.Text,
properties: { text: "" }, //Type A
},
]
Playground Link
Instantiate a generic type with every key of a different type
The solution is to make TypeScript use each constituent of keyof Foo
separately:
type FooPropertyData<T extends keyof Foo = keyof Foo> = T extends T ? FooProperty<T> : never;
This phenomenon can be demonstrated in the following:
type All<T> = Set<T>;
type Each<T> = T extends T ? Set<T> : never;
type AllIn = All<"1" | "2">; // Set<"1" | "2">
type EachIn = Each<"1" | "2">; // Set<"1"> | Set<"2">
Playground
Get the type of a specific key of generic type in TypeScript
You can add a constraint on U
so that it is a subset of the keys of T
using extends
. V
could represent the updateKey
type and also have the same constraint.
Simplifying your problem to a funtion updateObject
instead of updateArray
it would become:
function updateObject<
T,
U extends keyof T,
V extends keyof T,
>(
obj: T,
testKey: U,
testValue: T[U],
updateKey: V,
updateValue: T[V],
testFailValue?: T[V]
) {
if (obj[testKey] === testValue) {
obj[updateKey] = updateValue;
} else if (testFailValue !== undefined) {
obj[updateKey] = testFailValue;
}
}
updateObject({aString: 'hello', aNumber: 42}, 'aString', 'hello', 'aNumber', 23);
Generic type for object values
If I understand you correctly what you need is
function f<T>(input: {[P in keyof T]: Fn<T[P]>}): void {
Two equivalent generic types are treated differently in function body
The type InferredPermittedKeysError
is defined as a subtype of keyof PermittedObj
, and PermittedObj
is any subtype of Pick<AllKeysObj, GoodKeys>
, which means it can have arbitrary properties in addition to GoodKeys
. So InferredPermittedKeysError
could be an arbitrary property name, it does not have to be a subtype of GoodKeys
.
For example:
- Suppose
AllKeysObj
is just equal toAnObjectWithAllKeys
. - Suppose also that
PermittedObj
is the type{goodkey1: string, goodkey2: string, foobar: string}
, which is indeed a subtype ofPick<AllKeysObj, GoodKeys>
. - Then
keyof PermittedObj
would be the union type'goodkey1' | 'goodkey2' | 'foobar'
. - Then suppose
InferredPermittedKeysError
is the type'foobar'
, which is allowed because it is a subtype of that union type. - Of course,
'foobar'
does not extendGoodKeys
.
In contrast, InferredPermittedKeysNOError
must indeed be a subtype of GoodKeys
, because it is defined as a subtype of keyof Pick<AllKeysObj, GoodKeys>
which is equal to the type GoodKeys
. So in fact your two generic types are not equivalent; your Id
function is giving the wrong result here.
To confirm, the following call is allowed, with no type errors:
// const test: ['foobar', 'goodkey1']
const test = genericFunction<
AnObjectWithAllKeys,
{goodkey1: string, goodkey2: string, foobar: string},
'foobar',
'goodkey1'
>();
Playground Link
Generic class with two parameters
You need two types of Geneerics:
public class Duo<P,Q> {
P first;
Q second;
public Duo(P one , Q two) {
this.first = one;
this.second = two;
}
}
Later you can use as follows:
Duo<String, Integer> duo = new Duo<>("Hello", 5);
Related Topics
Generating Random Numbers With Swift
Why Non Optional Any Can Hold Nil
Delete Data from Coredata Swift
Padding a Swift String for Printing
Programmatically Navigate to New View in Swiftui
In Swift, How to Convert a String to an Enum
Can the Height of the Uisearchbar Textfield Be Modified
What Are the Differences Between Throws and Rethrows in Swift
Dismiss Keyboard with a Uitextview
How to Scale Text to Fit Parent View with Swiftui
How to Set the Blurradius of Uiblureffectstyle.Light
Open Uidatepicker Programmatically in iOS 14
Can Associated Values and Raw Values Coexist in Swift Enumeration
Hide Navigation Bar Without Losing Swipe Back Gesture in Swiftui
Convert Between Decimal, Binary and Hexadecimal in Swift