How to get properties of {[key in keyof T]: T[key]} type?
import { getType, Type } from "tst-reflect"
export class Temp {
id: string
email: string
}
type T = {
[key in keyof Temp]: Temp[key]
}
function foo<T>() {
const type: Type = getType<T>()
console.log(type)
}
foo<T>()
Following code produces
this output
TypeActivator {
_name: 'T',
_fullName: 'T',
_kind: 5,
_constructors: [],
_properties: [],
_methods: [],
_decorators: [],
_typeParameters: [],
_ctor: undefined,
_ctorDesc: ConstructorImportActivator {},
_interface: undefined,
_isUnion: false,
_isIntersection: false,
_types: [],
_literalValue: undefined,
_typeArgs: [],
_conditionalType: undefined,
_indexedAccessType: undefined,
_genericTypeConstraint: undefined,
_genericTypeDefault: undefined,
_baseType: TypeActivator {
_name: 'Object',
_fullName: 'Object',
_kind: 2,
_constructors: [],
_properties: [],
_methods: [],
_decorators: [],
_typeParameters: [],
_ctor: [Function: ctor],
_ctorDesc: ConstructorImportActivator {},
_interface: undefined,
_isUnion: false,
_isIntersection: false,
_types: [],
_literalValue: undefined,
_typeArgs: [],
_conditionalType: undefined,
_indexedAccessType: undefined,
_genericTypeConstraint: undefined,
_genericTypeDefault: undefined,
_baseType: undefined
}
}
Does it work with Omit and Pick? (I see the same output for them because they are implemented in similar way I did it in example)
Hello @Igorjan94, this is an issue with the current implementation. These types are not handled properly; there is a new big upcoming update which change the way how are these types handled. It should be possible to hotfix this. I can do it in the current version if you want.
Thank you @Hookyns! No need to hotfix, I'll wait for update, it works fine in my current scenario, I was just testing how it works on different types I have
@Hookyns is the future changes on the devel branch? I have a potential fix to this problem along with a couple more changes. When I get time I can port those fixes to the devel branch.
@joeferner it can be main, I do just minor fixes in the main and devel cuz I work on the next version which change the transformer a lot.
@Igorjan94, @joeferner
Should be fixed in [email protected] and [email protected].
Works like a charm!
Only bug I found during some testing, that Omit fails when using [key: string]: any extension in class:
function foo<T>() {
const type: Type = getType<T>()
console.log(type)
}
export class Temp {
id?: string
email?: string
// [key: string]: any // <--------
}
foo<Omit<Temp, 'email'>>()
Example output
TypeActivator {
_name: 'Omit',
_fullName: 'Omit',
_kind: 5,
_constructors: [],
_properties: [],
_indexes: [
IndexInfo {
_keyType: [LazyType],
_type: [LazyType],
readonly: false
},
IndexInfo {
_keyType: [LazyType],
_type: [LazyType],
readonly: false
}
],
_methods: [],
_decorators: [],
_typeParameters: [],
_ctor: undefined,
_ctorDesc: ConstructorImportActivator {},
_interface: undefined,
_isUnion: false,
_isIntersection: false,
_types: [],
_literalValue: undefined,
_typeArgs: [],
_conditionalType: undefined,
_indexedAccessType: undefined,
_functionType: undefined,
_genericTypeConstraint: undefined,
_genericTypeDefault: undefined,
_isGenericType: false,
_genericTypeDefinition: undefined,
_baseType: LazyType {
typeResolver: [Function (anonymous)],
resolvedType: TypeActivator {
_name: 'Object',
_fullName: 'Object',
_kind: 2,
_constructors: [],
_properties: [],
_indexes: [],
_methods: [],
_decorators: [],
_typeParameters: [],
_ctor: [Function: ctor],
_ctorDesc: ConstructorImportActivator {},
_interface: undefined,
_isUnion: false,
_isIntersection: false,
_types: [],
_literalValue: undefined,
_typeArgs: [],
_conditionalType: undefined,
_indexedAccessType: undefined,
_functionType: undefined,
_genericTypeConstraint: undefined,
_genericTypeDefault: undefined,
_isGenericType: false,
_genericTypeDefinition: undefined,
_baseType: undefined
}
}
}
If marked line is uncommented, then type is wrong, otherwise $-$ works as intended
Okay,.. I think I got it.
It works like intended IMHO because Omit creates new type alias which is object {} and that object have some properties but it has indexer [key: string]: any too which hides all other properties with string key. Those properties are subset of that indexer so TypeScript throws it away, because it is redundant information.
Try this:
function foo<T>() {
const type: Type = getType<T>()
console.log(type)
}
export class Temp {
id?: string
email?: string
[key: symbol]: any // <-------- SYMBOL key
}
foo<Omit<Temp, 'email'>>()
Now it generates the id property, because it is not hidden under indexer anymore, because it does not match key type.
Generated metadata for that:
{
n: "Omit",
k: 5,
props: [{
n: "id",
t: _ßr.Type.store.wrap({
n: "string",
k: 2,
ctor: function () {
return Promise.resolve(String);
}
}),
am: 2,
acs: 0,
ro: false,
o: true
}],
indxs: [{
k: _ßr.Type.store.wrap({
n: "symbol",
k: 2,
ctor: function () {
return Promise.resolve(Symbol);
}
}),
t: _ßr.Type.store.wrap({
n: "any",
k: 2
}),
ro: false
}]
}
Ah yeah, I see. Didn't notice that typescript throws it away in indexer (anyway, I don't use these indexers now, it was added for migrating)
Thanks for making this amazing package, really appreciate the effort!