You're seeing channels and samplers there, not individual keyframes. In this case, one animation is simultaneously targeting the translation, rotation, and scale channels of the same node, with three separate "samplers" (sets of keyframes per channel).
Not shown above, your glTF file has a section called
accessors that tells viewers how to slice out portions of binary data from an associated
.bin file. The
.bin file contains mostly mesh position/normal/UV data, but also contains the keyframe times and values.
So in the above snippet, that first channel targets the
translation of node 3 with sampler 0 (the first sampler). The sampler there asks for
LINEAR interpolation of keyframes from animation times (
input: 8) for translation keyframe values (
output: 9). In the
accessors section, accessors 8 and 9 (using zero-based indexing) are references to the keyframe times (in 8) and values (in 9). They are separate because the data type of the output depends on what's being targeted (rotations are vec4 quaternions for example, while translations and scales are vec3, and the input times are just floats).
accessors in question (8 and 9 for example) will contain a value
"count" that effectively tells you the number of keyframes. If you have 5 keyframes for example, accessor 8 should have
"count": 5 keyframe times, and accessor 9 will also have
"count": 5 keyframe values. The glTF Validator will flag an error if these counts don't match.