function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) { return obj[key];}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "e");
기본적인 동작
“e”
가 Key extends keyof Type
에 할당 가능한지 검사하는 로직
inferTypeArguments
⇒ inferTypes
⇒ getInferredTypes
**
Key extends keyof Type
의 타입을 구하는 코드
//getInferredTypes
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
if (constraint) {
// 1
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
// If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint.
inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint;
}
}
instantiateType
⇒ instantiateTypeWithAlias
⇒ instantiateTypeWorker
⇒ getMappedType
을 호출하고 getMappedType
은 createInferenceContextWorker
로 만든makeNonFixingMapperForContext
를 호출한다.(1) 참고
(2) Key extends keyof Type
의 Type
과 sources
(3) 의 Type
이 같을 경우 targets
를 호출해서
(5) 가 호출된다.
(5)는 { a : 1 }
이라는 타입을 다시 얻어오고
instantiateType
⇒ instantiateTypeWithAlias
⇒ instantiateTypeWorker
⇒ **getIndexType
⇒ getLiteralTypeFromProperties
를 호출해서 결국 a
이라는 타입을 얻어낸다.
// instantiateTypeWorker
if (flags & TypeFlags.TypeParameter) {
const mappedType = getMappedType(type, mapper);
return mappedType
}
//
function getMappedType(type: Type, mapper: TypeMapper): Type {
switch (mapper.kind) {
//...
case TypeMapKind.Deferred: {
const sources = mapper.sources;
const targets = mapper.targets;
for (let i = 0; i < sources.length; i++) {
if (type === sources[i]) { //2
return targets[i](); // 3
}
}
return type;
}
//...
}
}
//createInferenceContextWorker
createInferenceContextWorker
function makeNonFixingMapperForContext(context: InferenceContext) {
return makeDeferredTypeMapper(
map(context.inferences, i => i.typeParameter), //4
map(context.inferences, (_, i) => () => {
return getInferredType(context, i); //5
}),
);
}
function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext {
const context: InferenceContext = {
inferences,
signature,
flags,
compareTypes,
mapper: reportUnmeasurableMapper, // initialize to a noop mapper so the context object is available, but the underlying object shape is right upon construction
nonFixingMapper: reportUnmeasurableMapper,
};
context.mapper = makeFixingMapperForContext(context);
context.nonFixingMapper = makeNonFixingMapperForContext(context);
return context;
}